/*
 * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.tribuo.clustering.hdbscan;

import com.oracle.labs.mlrg.olcut.util.Pair;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.tribuo.DataSource;
import org.tribuo.Dataset;
import org.tribuo.Example;
import org.tribuo.Feature;
import org.tribuo.Model;
import org.tribuo.MutableDataset;
import org.tribuo.Prediction;
import org.tribuo.clustering.ClusterID;
import org.tribuo.clustering.ClusteringFactory;
import org.tribuo.clustering.evaluation.ClusteringEvaluation;
import org.tribuo.clustering.evaluation.ClusteringEvaluator;
import org.tribuo.clustering.example.ClusteringDataGenerator;
import org.tribuo.clustering.example.GaussianClusterDataSource;
import org.tribuo.data.columnar.FieldProcessor;
import org.tribuo.data.columnar.ResponseProcessor;
import org.tribuo.data.columnar.RowProcessor;
import org.tribuo.data.columnar.processors.field.DoubleFieldProcessor;
import org.tribuo.data.columnar.processors.response.EmptyResponseProcessor;
import org.tribuo.data.csv.CSVDataSource;
import org.tribuo.datasource.ListDataSource;
import org.tribuo.evaluation.TrainTestSplitter;
import org.tribuo.impl.ArrayExample;
import org.tribuo.math.distance.DistanceType;
import org.tribuo.math.la.DenseVector;
import org.tribuo.math.la.SGDVector;
import org.tribuo.math.neighbour.NeighboursQueryFactory;
import org.tribuo.math.neighbour.NeighboursQueryFactoryType;
import org.tribuo.math.neighbour.kdtree.KDTreeFactory;
import org.tribuo.provenance.DataSourceProvenance;
import org.tribuo.provenance.SimpleDataSourceProvenance;
import org.tribuo.protos.core.ModelProto;
import org.tribuo.test.Helpers;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

/**
 * Unit tests with small datasets for Hdbscan
 */
public class TestHdbscan {

    private static final HdbscanTrainer t = new HdbscanTrainer(5, DistanceType.L2.getDistance(), 5,2, NeighboursQueryFactoryType.KD_TREE);

    @BeforeAll
    public static void setup() {
        Logger logger = Logger.getLogger(HdbscanTrainer.class.getName());
        logger.setLevel(Level.WARNING);
        logger = Logger.getLogger(org.tribuo.util.infotheory.InformationTheory.class.getName());
        logger.setLevel(Level.WARNING);
    }

    @Test
    public void testInvocationCounter() throws URISyntaxException {
        ClusteringFactory clusteringFactory = new ClusteringFactory();
        ResponseProcessor<ClusterID> emptyResponseProcessor = new EmptyResponseProcessor<>(clusteringFactory);
        Map<String, FieldProcessor> regexMappingProcessors = new HashMap<>();
        regexMappingProcessors.put("Feature1", new DoubleFieldProcessor("Feature1"));
        regexMappingProcessors.put("Feature2", new DoubleFieldProcessor("Feature2"));
        regexMappingProcessors.put("Feature3", new DoubleFieldProcessor("Feature3"));
        RowProcessor<ClusterID> rowProcessor = new RowProcessor<>(emptyResponseProcessor,regexMappingProcessors);
        URI trainData = this.getClass().getResource("/basic-gaussians.csv").toURI();
        CSVDataSource<ClusterID> csvSource = new CSVDataSource<>(Paths.get(trainData),rowProcessor,false);
        Dataset<ClusterID> dataset = new MutableDataset<>(csvSource);

        HdbscanTrainer trainer = new HdbscanTrainer(7, DistanceType.L2.getDistance(), 7,4, NeighboursQueryFactoryType.BRUTE_FORCE);
        for (int i = 0; i < 5; i++) {
            HdbscanModel model = trainer.train(dataset);
        }

        assertEquals(5,trainer.getInvocationCount());

        trainer.setInvocationCount(0);

        assertEquals(0,trainer.getInvocationCount());

        Model<ClusterID> model = trainer.train(dataset, Collections.emptyMap(), 3);

        assertEquals(4, trainer.getInvocationCount());
    }

    @Test
    public void testEndToEndTrainWithCSVData() throws URISyntaxException {
        ClusteringFactory clusteringFactory = new ClusteringFactory();
        ResponseProcessor<ClusterID> emptyResponseProcessor = new EmptyResponseProcessor<>(clusteringFactory);
        Map<String, FieldProcessor> regexMappingProcessors = new HashMap<>();
        regexMappingProcessors.put("Feature1", new DoubleFieldProcessor("Feature1"));
        regexMappingProcessors.put("Feature2", new DoubleFieldProcessor("Feature2"));
        regexMappingProcessors.put("Feature3", new DoubleFieldProcessor("Feature3"));
        RowProcessor<ClusterID> rowProcessor = new RowProcessor<>(emptyResponseProcessor,regexMappingProcessors);
        URI trainData = this.getClass().getResource("/basic-gaussians.csv").toURI();
        CSVDataSource<ClusterID> csvSource = new CSVDataSource<>(Paths.get(trainData),rowProcessor,false);
        Dataset<ClusterID> dataset = new MutableDataset<>(csvSource);

        NeighboursQueryFactory kdTreeFactory = new KDTreeFactory(DistanceType.L2.getDistance(), 4);
        HdbscanTrainer trainer = new HdbscanTrainer(7,7,kdTreeFactory);
        HdbscanModel model = trainer.train(dataset);

        List<Integer> clusterLabels = model.getClusterLabels();
        List<Double> outlierScores = model.getOutlierScores();

        int [] expectedIntClusterLabels = {3,5,4,5,0,3,4,4,5,3,4,5,5,5,3,5,4,5,5,5,5,0,5,5,5,5,0,5,4,0,3,3,4,5,3,5,5,3,5,4,3,5,5,5,3,3,3,3,3,3,5,5,4,5,4,5,3,5,4,5,4,0,4,4,5,5,4,5,4,4,5,5,3,3,4,5,3,5,5,3,5,5,5,4,3,4,5,5,3,3,4,5,4,4,5,5,3,3,5,5,4,4,5,4,5,5,4,5,3,3,4,3,5,3,3,4,4,3,5,4,5,3,3,5,5,3,4,4,3,5,5,0,3,5,4,3,5,5,3,4,4,5,4,4,5,3,5,3,4,5,3,5,5,3,5,5,3,4,4,4,3,3,4,4,5,5,5,5,3,5,3,5,5,3,5,3,5,5,5,3,5,5,5,5,4,4,4,5,5,4,5,0,5,3,5,5,3,4,4,4,5,4,3,5,5,5,4,5,4,5,5,3,5,4,5,5,5,4,3,3,3,5,5,5,5,3,5,4,5,4,3,5,4,5,5,0,3,3,5,3,3,0,3,5,5,0,4,5,0,5,5,5,5,3,3,5,0,3,5,3,5,4,4,5,5,5,4,5,4,5,5,5,3,5,5,4,4,4,4,4,4,5,5,3,5,5,3,5,4,5,5,5,4,4,4,3,4,3,5,3,5,3,4,4,4,3,4,5,4,5,5,4,3,4,4,4,3,5,3,5,4,5,5,3,5,5,3,3,3,0,4,3,4,5,4,5,3,5,4,3,0,3,5,3,5,4,4,5,0,4,3,5,4,0,5,4,4,3,4,3,3,5,5,5,5,3,5,3,4,4,4,4,3,4,3,5,3,5,3,3,5,3,5,5,5,3,4,5,3,5,4,5,5,5,5,5,4,5,3,4,3,3,5,5,5,4,5,4,5,5,5,5,4,5,5,5,4,5,3,5,3,5,0,3,3,5,3,4,5,5,5,5,3,4,3,3,0,5,5,0,3,5,5,5,5,3,5,5,3,5,5,5,5,5,4,4,5,4,5,5,0,5,5,3,3,3,5,3,0,5,3,5,5,4,5,5,0,5,5,5,5,3,5,5,5,4,3,5,4,4,4,5,5,5,4,5,5,4,5,3,5,4,4,4,3,3,5,5,3,4,4,5,5,3,5,3,5,4,5,4,3,3,5,3,5,3,3,3,4,3,4,5,5,5,4,4,4,5,5,4,3,4,5,4,5,3,5,0,5,4,5,4,5,5,5,4,4,5,3,4,3,5,5,5,3,5,5,3,5,3,5,4,4,4,5,5,5,4,3,5,5,3,3,5,3,5,4,3,4,5,5,5,5,5,5,3,4,4,4,5,5,5,3,5,5,5,3,3,3,5,3,5,5,4,4,4,4,5,5,5,5,5,4,3,5,3,5,0,3,5,5,5,3,5,5,4,0,4,0,3,5,5,3,3,5,5,3,3,5,5,4,3,3,5,5,5,5,3,5,5,5,4,5,4,5,5,3,3,4,5,3,4,5,5,5,5,5,5,5,5,5,3,5,4,5,4,5,0,5,5,4,5,4,4,3,5,3,4,3,3,5,3,3,5,4,5,5,5,5,4,0,3,3,4,4,3,5,4,3,3,4,5,5,4,3,4,5,4,5,5,5,4,5,3,3,3,4,4,4,3,4,5,5,5,3,5,3,5,5,4,3,3,5,4,5,3,3,5,4,3,3,5,4,5,5,4,5,4,5,3,3,5,5,5,0,5,3,4,3,5,4,5,5,5,5,5,5,5,4,4,5,3,0,5,4,4,4,5,5,5,3,5,5,5,4,5,4,5,5,5,5,5,0,5,5,3,3,5,3,4,5,3,4,4,5,3,5,5,3,5,3,5,5,5,5,3,4,3,3,5,3,4,4,3,5,4,5,5,4,4,3,4,5,5,4,5,3,5,3,4,3,5,0,4,4,4,5,4,5,4,3,5,3,0,4,4,5,5,5,3,4,3,5,5,3,3,3,4,5,5,5,3,4,5,0,4,5,5,3,5,3,0,3,5,4,5,5,4,5,5,5,5,5,4,4,4,3,4,5,4,5,4,5,4,4,4,3,4,5,4,5,3,5,5,3,4,5,5,5,5,4,5,3,3,3,3,5,4,5,5,5,3,5,3,5,5,5,3,4,5,5,5,5,5,4,5,5,5,3,0,5,3,3,5,5,3,5,5,4,3,3,3,3,0,3,4,5,3,4,5,5,4,5,3,3,3,5,5,3,4,3,5,4,5,5,5,3,5,3,5,5,5,5,5,5,4,3,5,3,3,4,5,5,4,4,3,5,4,5,4,5,5,5,5,5,3,3,0,5,3,5,4,5,5,5,5,3,5,5,3,5,4,4,5,3,5,4,3,4,5,3,5,5,4,3,5,3,3,5,5,5,3,3,3,5,5,5,3,4,5,5,5,5,5,5,5,4,5,3,5,4,3,3,3,5,5,5,5,4,5,4,5,4,5,4,3,5,0,5,5,0,4,5,5,4,3,5,3,4,5,3,5,5,5,3,5,5,5,4,5,5,3,3,5,5,5,5,4,5,4,5,3,4,5,4,5,5,0,5,4,5,3,3,4,5,3,5,5,5,3,4,3,4,3,4,4,5,3,5,5,0,3,4,3,5,5,4,5,5,4,5,3,5,3,5,5,3,5,3,4,5,5,3,5,4,5,5,5,4,4,5,5,5,3,4,3,5,4,4,5,5,5,3,3,5,4,5,5,3,3,5,4,5,4,4,4,3,3,3,5,3,3,3,5,3,5,5,5,4,5,5,3,4,3,3,3,5,3,5,4,4,5,3,0,5,3,3,5,5,4,5,3,4,4,5,5,4,4,5,3,4,4,5,5,5,5,3,5,3,3,5,5,3,5,5,3,3,3,5,5,4,3,5,4,4,3,5,5,3,0,4,4,4,3,4,5,5,5,5,3,5,3,5,3,5,4,5,3,4,3,5,5,5,5,4,3,5,5,3,5,5,4,4,5,3,5,3,5,4,3,5,5,5,5,4,4,3,5,4,5,5,5,5,5,5,3,5,4,5,5,4,5,3,4,4,5,3,4,5,5,5,3,4,4,4,5,5,4,5,3,3,4,5,3,5,5,4,5,5,5,4,5,5,3,4,5,5,0,4,4,3,5,5,5,4,4,5,5,4,5,5,4,3,4,3,5,0,3,5,4,5,3,3,5,4,3,5,5,5,4,5,3,5,5,5,4,5,5,0,5,5,5,4,3,4,5,0,5,5,3,5,0,5,5,5,5,5,5,4,3,5,3,4,0,5,5,0,5,5,3,5,5,3,5,5,5,5,4,3,3,5,4,3,3,3,5,5,5,5,4,3,3,5,5,5,3,5,3,3,4,5,5,5,4,5,5,5,5,5,5,5,5,4,5,3,5,5,4,5,5,4,3,5,5,5,5,5,4,5,0,5,3,5,3,3,5,5,4,5,5,5,5,4,5,4,5,5,4,5,5,0,4,5,5,4,4,5,5,5,5,4,5,5,5,3,5,5,5,4,5,4,4,5,4,4,4,5,4,3,3,3,4,3,5,4,3,5,5,3,3,5,3,4,3,5,5,5,5,3,5,5,3,5,4,3,0,5,4,4,3,5,4,4,3,5,4,5,5,5,4,3,4,5,5,4,3,3,5,5,5,5,5,5,3,5,3,5,5,4,4,5,5,3,5,5,5,5,5,5,3,5,3,0,5,3,3,5,5,5,5,3,3,4,3,4,5,5,3,5,4,5,4,3,3,4,5,5,3,5,4,3,5,3,3,4,0,5,5,5,4,4,5,3,3,5,5,5,5,5,5,3,5,5,5,4,4,5,5,5,3,5,5,3,0,4,4,3,4,4,4,5,0,5,3,5,5,4,5,5,3,5,4,3,5,5,5,4,4,5,5,5,5,3,5,4,4,5,4,5,5,5,3,4,3,5,5,4,5,4,4,0,4,4,4,4,4,3,5,3,5,4,5,4,4,3,3,3,5,5,5,5,5,3,5,3,5,4,5,4,4,4,3,3,3,3,5,5,5,4,3,5,3,5,3,4,5,5,5,4,5,3,3,3,4,3,3,5,4,5,3,5,3,5,5,3,5,3,5,3,4,4,4,3,5,5,5,3,4,4,3,5,3,4,4,4,4,5,3,5,5,4,5,5,5,5,3,5,5,5,4,3,4,4,5,4,4,3,5,5,5,5,3,5,5,5,4,4,3,3,3,5,4,3,0,4,4,5,0,5,5,3,3,4,5,4,5,3,3,5,4,5,5,3,5,4,5,5,5,5,4,4,5,5,5,5,5,0,3,4,5,4,4,5,3,4,5,5,5,3,3,3,0,0,3,3,5,3,3,5,5,3,5,5,5,4,5,4,3,4,3,0,3,5,4,4,3,5,4,4,4,3,5,5,3,4,4,3,3,4,5,4,3,3,3,4,5,3,3,4,4,5,3,5,5,3,5,4,4,5,3,3,3,3,4,0,5,4,5,5,4};
        List<Integer> expectedClusterLabels = Arrays.stream(expectedIntClusterLabels).boxed().collect(Collectors.toList());

        double [] expectedDoubleOutlierScores = {0.47358175271351555,0.5414658310482977,0.31853747871968563,0.4280760238473448,0.7536843521184464,0.3601622156931149,0.5272767130061837,0.5259973899834453,0.636222606790072,0.3000242767751776,0.42195026500148336,0.04620516071879277,0.0804863130050969,0.36782631972078605,0.2695742331327128,0.43552883184782476,0.43905666395399756,0.37935517113968176,0.6449092021603602,0.5676065051695158,0.4483291690445501,0.7729968587684631,0.0,0.21731496412888562,0.581117423864291,0.6308335986889171,0.7843465403995961,0.3003135504775737,0.603355578459364,0.7566963515476114,0.16871756538011295,0.6224928359010734,0.5298508811322651,0.0,0.31306681440424333,0.3812638737290107,0.5255720233717707,0.4112747353567219,0.47509756458767316,0.6125207319619739,0.6170543537831388,0.3535120791216183,0.0,0.5034420938549125,0.28989499879808245,0.29224627768607514,0.0,0.31658607391770566,0.11621821150048195,0.32681227425828385,0.40827088653349086,0.38891555341987816,0.29562553241510536,0.14912292196340138,0.743501218517193,0.32546418038027936,0.4055250865928418,0.0,0.45405355759497423,0.4681005824053899,0.6544174567682297,0.7783330694268489,0.6252627098123447,0.6070426305004005,0.07672353637854812,0.0,0.5387962682486258,0.6481435074684916,0.490506760667182,0.3871027615917967,0.653648938906807,0.0,0.5895947175711314,0.36599358407440996,0.6232332570885072,0.5187753107469597,0.5826702556968544,0.6444693945436082,0.27236826028499506,0.0,0.34664073595193734,0.5977023632181397,0.5096592353353864,0.269904364115535,0.16871756538011295,0.4743674961344725,0.5936321631410117,0.21516462146260296,0.0,0.737055324600702,0.5264388495833144,0.22732561863527845,0.3067796703101542,0.43905666395399756,0.47971852678268034,0.0,0.4112747353567219,0.3409635687892707,0.47381866965726305,0.30376928888062393,0.5834707736876774,0.408517388812911,0.5966674138239424,0.37624086873447904,0.3990832100389875,0.12154778462865656,0.33747617335487545,0.0,0.3456502127939042,0.0,0.3681613030558898,0.4962345880567618,0.42361379464816384,0.5191111911339586,0.2796421977643141,0.3836246325205478,0.0,0.5841840456402354,0.0,0.4580833001113499,0.29945586899686516,0.0,0.7060160641811467,0.2369453709051733,0.06492324355125823,0.3861896255681202,0.5556401813233378,0.0,0.7222130100294228,0.32446676707111055,0.4357740061945765,0.8403289688601812,0.446397883570942,0.25435336247371376,0.5762356846189509,0.3456502127939042,0.16699586735690297,0.500191890833944,0.20836641600896022,0.6206463762011754,0.3667666392115102,0.4324013942368624,0.5991165699175696,0.3871310408096563,0.39335742422941844,0.47698006683148797,0.26418664607144837,0.4071448942368182,0.5227403143437382,0.4185983644477421,0.5594270332986124,0.6230867835968079,0.37496236017491336,0.7555429921879805,0.6699942010322993,0.5127286468158467,0.22923187910248222,0.6275572804245837,0.06105242928880117,0.4609696442471398,0.2948004212500368,0.2727987081884128,0.37956761534921934,0.30573664121521904,0.7220745542200588,0.19092041195838683,0.3432090250204166,0.2063486508048732,0.013925122169310966,0.0,0.0,0.0,0.06492324355125823,0.44426589083652057,0.44398591628262796,0.37891294036812484,0.7156836869466953,0.0,0.2815040444723871,0.31197985827951213,0.2891995980313147,0.5512983085307032,0.31421939280536004,0.4377058742150195,0.5818616147463891,0.5018589425014524,0.0,0.43828168695823744,0.41685484146125196,0.38291482436319646,0.26732125164117826,0.7768965057833135,0.4583041966983865,0.44456048652206126,0.3741683513565959,0.533346187911755,0.7587434939764999,0.13410101110369166,0.42674550330613104,0.7351917533857362,0.5713041005281074,0.6405165802078032,0.5933533497269812,0.5956793667033696,0.6517825205768181,0.5429686245606076,0.40760010031768557,0.3265855728027738,0.5322524670414263,0.5310138807891505,0.0,0.45609070594174217,0.6593186724760913,0.40218042707482093,0.7135260731909046,0.0,0.4924356904948839,0.33206417789286724,0.5933853373609538,0.3748651677610172,0.6254229089345361,0.39597398385394467,0.008171288900179485,0.1496330958893356,0.32925122056086287,0.40381249866163804,0.04799339719711404,0.45150410521081097,0.6043492843608917,0.40551377067949423,0.26097697111644147,0.21516462146260296,0.6201246269431693,0.48193784898644665,0.5266986456719284,0.8322088853831846,0.5296135420884414,0.5110852514237674,0.5469021659826454,0.3456502127939042,0.5386953819112004,0.7784182366725912,0.2278234705572778,0.4424763817633829,0.7150819204214296,0.7538321636560839,0.0,0.4771358781074473,0.7489119098515302,0.29946053564660136,0.6042383596284573,0.461764258382828,0.14912292196340138,0.5149256672122535,0.6343721193118133,0.3917923406934356,0.8074729866466948,0.28989499879808245,0.49037030144326954,0.7309622306419712,0.47137478106163877,0.31931559059510217,0.28775431379151906,0.30549132501511833,0.6340610575565697,0.3953913856557185,0.42316455222460936,0.2690894183464325,0.3177264056799928,0.43415995493910475,0.506638357473808,0.6990082287262445,0.5505860967266402,0.4816621654331692,0.6445108484123541,0.2448370506161358,0.5475848764311885,0.24663596095828988,0.49943671538145995,0.4637944321138555,0.5262201973052165,0.6505650981040596,0.701466874912067,0.42689743788477885,0.5396433274683845,0.4776041796757132,0.3310780648601609,0.31648418053759364,0.6118168056299457,0.3986352885793346,0.0,0.6458854232442651,0.4042693647851897,0.6253073810590905,0.030066809762104074,0.3493040196609468,0.6552839043795295,0.3456502127939042,0.3535496611554798,0.2207349697015366,0.6154008035515187,0.6045076456433015,0.5426248185164286,0.7169609987578835,0.4486019807190156,0.4455087183994092,0.7006713157437083,0.34174552110905276,0.6656975918340791,0.3284956875437921,0.42002499215129263,0.36993561874168923,0.3687581876367665,0.44424924669822174,0.29836510432778773,0.31455738296793045,0.23729243310901027,0.21516462146260296,0.1980858670864919,0.3365306429058218,0.24995348289246522,0.39484971592847373,0.6576646032648548,0.5479046532061724,0.2967447898021014,0.3418391400708265,0.3839887817757234,0.3519283734067741,0.22923187910248222,0.8001273911109451,0.49705026305184596,0.38225496965262873,0.53914939194177,0.48761908580442936,0.6418544558170016,0.30662140654113357,0.21855179634449917,0.4931293566573668,0.5783458284149787,0.0,0.7638535118781034,0.3624204074542483,0.2701534139882117,0.7594189772964117,0.5695348295152692,0.3667666392115102,0.4160924195296938,0.5569180416682643,0.7776533006774671,0.2000837140836903,0.48633934197199924,0.34174552110905276,0.7111270451945378,0.7895994397625472,0.2283896005703272,0.3939460185546144,0.49417560754156875,0.464691645899445,0.36572357312056525,0.0,0.3839887817757234,0.36305367292219415,0.3741683513565959,0.5084896108482566,0.16575812059028605,0.4225951359081882,0.3143792517940033,0.5067429952592745,0.0487514432337689,0.6669662401082497,0.4280361886438846,0.43386563397683353,0.5416206409141738,0.31928088848131353,0.12741992401463698,0.5822141614023605,0.6055550272678605,0.5776422244603738,0.4970267038737336,0.13023233472690932,0.3284956875437921,0.28989499879808245,0.592266021893906,0.3984040787215949,0.49922881456754953,0.5317723301954207,0.23128810948166578,0.3526660020106209,0.029347971609487877,0.2999535725433774,0.0,0.469887053155719,0.670226977385818,0.3672668668575686,0.5015555056496628,0.4085857346589076,0.4525315664190599,0.0,0.5105400540069525,0.4421357841437522,0.31658607391770566,0.3369461078522318,0.02773285125509206,0.5417179683725725,0.0576991377488314,0.22204797677633936,0.0,0.45809732122075875,0.26921794560895074,0.3195633140487657,0.3873683640266503,0.3082926292203588,0.5547005313946429,0.5057154073499082,0.4765447223291741,0.5845098021058535,0.0,0.2738860944950706,0.4324679970998656,0.31211705980815607,0.6347908457930689,0.18525063623712357,0.7798357236320714,0.26097697111644147,0.42106254339227944,0.5378064251110591,0.4873311828072008,0.6914084466972419,0.3350175591159461,0.6199553903601905,0.35448733323678416,0.6063259139226185,0.690657312622633,0.3802254424431216,0.2670037707718146,0.3874162195368408,0.8026191868263431,0.4678939719541557,0.5795563831019814,0.8043306999444119,0.4089243362601419,0.6323003476130089,0.0,0.0,0.311879770365313,0.006254727823924222,0.14912292196340138,0.7239915467402447,0.16871756538011295,0.4411338219017581,0.48221298536204915,0.2947832526838541,0.35513520468722715,0.3904290091452032,0.6395975448606019,0.47589983398875724,0.08877011102792942,0.5169689372644171,0.48213406880902177,0.0,0.8082677166402176,0.4922677742042706,0.5944274076658302,0.49515729128119745,0.825466290928847,0.0,0.37401373277278727,0.22371616934103422,0.7838509096070428,0.630656729728954,0.4494888079774554,0.0,0.4426781742253425,0.3892051586488292,0.13860627552095273,0.49750739084196827,0.7661220686027514,0.0,0.4963988970762506,0.6132440414398083,0.5737389221302394,0.3738471519240103,0.5187918707538988,0.5944330967810928,0.4595620492165915,0.26650659360152096,0.6051568335067139,0.6413296769660171,0.4316838204035055,0.021041213842302287,0.5462269069218768,0.3712819238193623,0.6141956298831273,0.0,0.32541052056123854,0.1576637307821378,0.3249620517856061,0.3651257124278885,0.19245638188636915,0.37448424125384494,0.3647643364817389,0.0,0.5814303866063273,0.6773910830484086,0.40800318903129196,0.5177181113022553,0.3580467970700235,0.08575367044706506,0.2778324875738022,0.3430808668001304,0.4266335795619267,0.6366964323474587,0.0,0.5105758746418961,0.0,0.5618372284748705,0.12646829619665623,0.6538961901468554,0.3545262603906427,0.5432904161164671,0.3601622156931149,0.250093797938734,0.4136198128134888,0.24125797661850068,0.27310212308386395,0.5416481617475357,0.4938300333019511,0.18967468982070068,0.7010439282429111,0.3089076300897101,0.6795219051837764,0.34664073595193734,0.35420966945200016,0.35768192154839074,0.7153808073331412,0.6771869651811608,0.677120494449309,0.6845570018610234,0.48518484093582603,0.3836246325205478,0.7323044818001779,0.0,0.23619829064472764,0.4712716152042339,0.0,0.3021327855295476,0.39015721745013754,0.7554587987544639,0.24822768816123908,0.413745928781042,0.23825296231784654,0.0,0.3923419763052197,0.4392727199165206,0.0,0.31928088848131353,0.3098614152791387,0.47567574761415954,0.38668912579614567,0.6354621531496921,0.16383227583528248,0.05246635243470976,0.1870139318759102,0.0,0.6415295074473144,0.20609843645540582,0.5164726440601963,0.8165507031399903,0.3449033588463204,0.570789604958164,0.39641599406810246,0.4943690132834516,0.0,0.4246603291703118,0.5168241717218262,0.16001248792274236,0.7070403531593957,0.33064512535378265,0.5866866583181796,0.4842762987844166,0.1412447876793511,0.4885653007199101,0.17742171646445526,0.21128858246120308,0.7246425646330104,0.38054271770789305,0.42955615334541974,0.38837234138454346,0.7218915977917744,0.4050264383107697,0.0,0.4041395748236205,0.12646829619665623,0.45036530982824874,0.548358116752813,0.27201798024213364,0.5413311998774006,0.4681140453013376,0.4160924195296938,0.7124363075265328,0.38353143252244837,0.5056143775709685,0.3692367230351188,0.3948985531485434,0.036971755744779955,0.305372373671393,0.614649633720348,0.2358917191458988,0.35721696422529414,0.12373894351399051,0.2563532167091731,0.38910953695089157,0.5825394961236873,0.5505477660210563,0.307973540200851,0.41835702709672484,0.6810331631074826,0.24471552753301118,0.7223516672072421,0.4520632835456354,0.35448733323678416,0.5966657123375374,0.42079011885433437,0.28289737773000867,0.5519815413081102,0.4005135049940618,0.4484716682058212,0.79270946887389,0.4216063123159455,0.6088004746195586,0.44717928204495916,0.24345698942084792,0.27050449902435314,0.5389150357399828,0.5273482379127558,0.5413311998774006,0.8285476016117026,0.528525241584312,0.7839427339781802,0.04923055396517728,0.3707483862540023,0.3837866626791563,0.38837816755874777,0.5478409953110283,0.3867611937625697,0.5103734383363709,0.400928574765699,0.45491551208332315,0.6773124520330367,0.5269751645580106,0.3387632195757464,0.4463959189823703,0.3412314112750898,0.0,0.5796011947781625,0.49391109297595615,0.303613742827598,0.3832014817548638,0.35495535150309865,0.04384108680937504,0.2690894183464325,0.3892051586488292,0.0,0.5182246276230229,0.4824138144675951,0.42906278112439844,0.4416371143081972,0.39961367734417963,0.6777855271993465,0.3000637654786039,0.19026953513182987,0.32651779705858053,0.271420089588442,0.5014305379452317,0.6230867835968079,0.3673888105983324,0.7124250069940696,0.4884249302908067,0.14912292196340138,0.4487406037564413,0.0,0.6753662651608616,0.3000281521211885,0.5097286991153387,0.4919367366620889,0.307973540200851,0.2864707971738649,0.7508854890224262,0.35091553378068674,0.21343677258672245,0.5425803523978154,0.22525840601413705,0.679690777499087,0.6729474148963777,0.7282095868644627,0.4672500162555244,0.7044288902098275,0.34670948497049425,0.3514654253195898,0.441662396411723,0.7147389215662775,0.3839887817757234,0.31571372025762023,0.371865166603941,0.5061076697187441,0.48125433911380033,0.3874442098214338,0.12076619090264895,0.38335278693511876,0.41249197679965377,0.7898292356050709,0.5815444881643806,0.60075814695453,0.0,0.0,0.13023233472690932,0.6337055987622278,0.4025422086922038,0.33546131400889667,0.2587888940592187,0.5664175891804494,0.33520713357537024,0.259432920934616,0.5867405520655916,0.2587888940592187,0.5033083487436193,0.2117626700593399,0.6587906274970755,0.6115633922928441,0.0,0.0,0.0,0.5056504922974333,0.3159504323824319,0.3839887817757234,0.21522091145386024,0.6954730677441794,0.4627961573775088,0.4257456035438163,0.5513101269971545,0.476647229462702,0.18416820074811935,0.0,0.4721412633683266,0.5473388916214317,0.5034420938549125,0.16871756538011295,0.5380586828824034,0.4261492431702657,0.6714918209725933,0.2464553365511717,0.36293632495112405,0.21516462146260296,0.3110493855357047,0.4812029699324305,0.4245745334470171,0.38967314869684866,0.3049626666568038,0.3098614152791387,0.46192415366574313,0.44916053156133007,0.4114860008687803,0.3518863516296503,0.0,0.5976131758500893,0.4736525482291779,0.5481353689825204,0.683251979088503,0.09663432889057066,0.7235452845604936,0.2153089051904491,0.45483309301099795,0.311879770365313,0.2176772660593751,0.7864765376738267,0.576036083086203,0.38214297023053034,0.6521870701831235,0.25870717242550656,0.6482171550650802,0.4786515503365818,0.0804863130050969,0.3568293291614032,0.34664073595193734,0.28381812710257803,0.3575686250517781,0.4483191693347306,0.3632190216549879,0.3670996456905741,0.43557436169813546,0.4515581428863833,0.4830424925464114,0.7560110106838798,0.57514269298302,0.4825626798679016,0.5831987224059128,0.40361909047023603,0.4178441209687199,0.0,0.3641789459960304,0.5795749487163394,0.6980648149582386,0.0576991377488314,0.24838525867789962,0.46540260204177475,0.625054835111005,0.12497274268138414,0.39664287586463587,0.3418602360765406,0.5476880701644403,0.7240190537807336,0.5528073786295289,0.7843465403995961,0.0,0.5687397614212621,0.5943137988537931,0.44916053156133007,0.6108115751867618,0.48907914078946124,0.6233161912145007,0.311879770365313,0.48461733608036817,0.4588927730482937,0.41932645749399344,0.0,0.49231583580717664,0.5734180359260712,0.0,0.5210280192451475,0.5015794237659166,0.5489418048109322,0.6987557223641838,0.3634350826313635,0.4273940091825391,0.3571832498149451,0.2506644346627148,0.48587691780635334,0.3456502127939042,0.7218887249554182,0.48450901239195,0.30832139557613814,0.7006713157437083,0.5404814617173812,0.37926915278169526,0.4215795903281747,0.3067796703101542,0.4697854275253076,0.17128563838715205,0.021041213842302287,0.4887760562266973,0.690986324522467,0.4277524804678684,0.3071342895296215,0.39352470710923604,0.6774894505857176,0.47000342590284294,0.3045511460387763,0.0912857343475364,0.6375303640190447,0.22490390292361262,0.009895402151539168,0.3000281521211885,0.7487707537790629,0.37096588620711546,0.31752367088807976,0.313551398576169,0.4689282144313608,0.6103724471134933,0.3227350807072843,0.42865014213428354,0.42202870044204677,0.0,0.6626209605616473,0.796310127399344,0.0,0.40218042707482093,0.2433458258089689,0.04667067256282831,0.23825296231784654,0.6097343190385305,0.611797405735002,0.05914335020781181,0.48195396363988063,0.424572298013397,0.6686853357882518,0.3636768327539607,0.5393272700296402,0.6079180167978628,0.0,0.47567574761415954,0.3167472811883112,0.40749409537327475,0.4217024807266213,0.3634054954338538,0.7496929032434594,0.3867579656237069,0.20060074536146477,0.40607335773962094,0.23357812183821092,0.2789333781664347,0.3736073131529789,0.8249501110472203,0.5319171725741765,0.4902019105761406,0.5072694782664345,0.5591687404281019,0.46061538831786275,0.6161165392876313,0.09663432889057066,0.19979285689975457,0.5070473236774482,0.23210538458334418,0.5668952491122194,0.33364478067757,0.021314157993151395,0.43386563397683353,0.8098565653475192,0.5703258208874638,0.20971226806420518,0.5743855790160797,0.4249442221577012,0.0,0.3219878631993316,0.0613883477662468,0.23128810948166578,0.7429308508577359,0.5047651337189344,0.6045709981494242,0.45871233826373703,0.6844350760170128,0.6495953653408698,0.2810303170277002,0.22210950812220076,0.36096207094872057,0.4915045563950171,0.3755633103396957,0.5885902046751965,0.13095575420822192,0.573947987934874,0.10683699690904058,0.4818077613861892,0.391506587624198,0.28973699342477544,0.10098548496967541,0.3899902103207685,0.375489089425478,0.3079971578748303,0.3721891932145144,0.31902103206609844,0.5710708032211278,0.3435892081899964,0.35989838086301873,0.05064199064053265,0.3218065191758813,0.6228332825949527,0.3369989106364166,0.15156049125160376,0.4526726144485661,0.5100520677251138,0.3971008501883473,0.6837853978865358,0.5138215435240225,0.44555462770565135,0.0,0.5304912668786743,0.1914749242830559,0.4213720497040293,0.37012510034096646,0.4707048526334472,0.7803236536487268,0.32222474968395887,0.25546678830793745,0.07895767088929595,0.5699172346083162,0.3284956875437921,0.3885161545370044,0.02170033331990273,0.3396177586485829,0.506847185467739,0.5190860744389649,0.3973405683869258,0.29906534000673657,0.4062740633691959,0.7694822381668954,0.3510955181077545,0.5902493651167116,0.6824557216441123,0.015150158490871979,0.5526098132853221,0.0,0.5153083371980647,0.06450496939423933,0.4223885221674304,0.3208648671839498,0.3426627732363028,0.3839887817757234,0.3898397248523402,0.36674442374867555,0.0,0.4859220797960221,0.2773187487514397,0.37408657262170364,0.6106207203052424,0.5308893639772336,0.0,0.18525063623712357,0.3640103014176189,0.5502403010859089,0.0764283212533079,0.32171751424416495,0.30662140654113357,0.5742984002662819,0.635575817965703,0.21430103027247993,0.5013206753014231,0.7487561355546246,0.6527316165124747,0.21024192708833367,0.6144510451972626,0.613713139729793,0.37266275623085554,0.4614150998565474,0.6132440414398083,0.438177656660124,0.462813608868366,0.3298591651956073,0.3209207612728636,0.5916821503457667,0.38409496468371396,0.6178463080771512,0.2947309863444706,0.271535884213859,0.47588027161081614,0.36528791684635475,0.0,0.5455788675271134,0.7459405573458152,0.7604959792315712,0.7065367439907762,0.4998307404683665,0.36440137993138655,0.5411256350778035,0.3494326940794764,0.4561785929208906,0.40748949841951376,0.46120107396619303,0.6240746889096774,0.5215154349365304,0.2815040444723871,0.325239732786501,0.31175336804484455,0.3831786307936871,0.4711524161547769,0.0,0.24245916384716704,0.5037910091610112,0.3785960623246245,0.28989499879808245,0.4590455664792802,0.6300677079889229,0.04927334848279319,0.3474729280531976,0.0,0.6352366658038269,0.21855179634449917,0.48055504929674553,0.6134611454996968,0.5617371240784204,0.4943181931548606,0.5345139843278115,0.3432090250204166,0.3176357078316202,0.2951997178567569,0.46776604397675103,0.3910952366000655,0.6148956798317169,0.19580197732062377,0.5828730085168237,0.307973540200851,0.2636664436319176,0.26015141405897024,0.45036530982824874,0.2791008840821435,0.34392296583963977,0.12646829619665623,0.32389994465562,0.676566267182856,0.49750739084196827,0.26097697111644147,0.5932130316797035,0.5035254245014051,0.3309082318222377,0.5296146206392793,0.37871784869460057,0.6978733929881893,0.43031286194284957,0.0,0.42043689162825093,0.6917081006661459,0.33974383297301713,0.4807387463553424,0.4652473386946798,0.30573664121521904,0.3589050115424707,0.4471929268191517,0.4072598163286715,0.5459419400712915,0.8021697298084183,0.5251927090905488,0.44447754406386353,0.7731410507299648,0.19025097456905338,0.5518653792435592,0.3412864662457583,0.6019294566282727,0.3839887817757234,0.25323602320148264,0.6999080948452584,0.41099112802685167,0.6067590063356723,0.5300702370805361,0.32461539749677193,0.30549132501511833,0.46421972765037545,0.4145719751280411,0.6194927617036287,0.6837913781935347,0.42697466064690504,0.5411256350778035,0.08394427358334722,0.31092704155262474,0.23729243310901027,0.22830249200893526,0.4825017191440689,0.47659181727783406,0.47567574761415954,0.6064484258966132,0.33364478067757,0.08359696517720483,0.45660428804284037,0.32054882517260386,0.2060931005812926,0.3694127105850752,0.19928420568351157,0.5270930771511028,0.3677319859511491,0.4728785870430714,0.8180268933901096,0.4764732646580715,0.39640051244962404,0.4512857522116185,0.33345346584946634,0.11452114146163428,0.3717615004456204,0.2176772660593751,0.5146621118544314,0.3413932862199621,0.3351070875322726,0.0,0.3021535524066322,0.28449310236680847,0.10878391943321775,0.375513342089725,0.3970656376671985,0.0,0.04958054124234079,0.39209390889749407,0.3553046156200449,0.0576991377488314,0.4831401716122625,0.7836716485755342,0.24873036395330927,0.48302282305326905,0.3257332037179078,0.4872750050314367,0.33597534754312897,0.27161450094574924,0.46165172112796016,0.259432920934616,0.46076649298453676,0.0,0.3825528965914782,0.4924167220173089,0.43316104112439024,0.5218041164020444,0.6813538440700735,0.33901598499143326,0.5828041418899708,0.5828730085168237,0.061747151088271335,0.410366445995761,0.5015978286259261,0.3274186508537139,0.44373815080302526,0.5534053520776185,0.48152705281678365,0.3134435010897727,0.34492574616375504,0.37878350828841,0.4396188965313158,0.4152633685504341,0.592819310083496,0.40989184632653075,0.3945655111599823,0.38291482436319646,0.3317917652527933,0.4215795903281747,0.44165107562066175,0.5427495515273517,0.5331599224578503,0.48363394480364774,0.38053796988095756,0.34823263853792685,0.13604424736935816,0.4275617156523288,0.48174087269232213,0.5702019394049207,0.5085227616075063,0.394032738673215,0.3456502127939042,0.4895635977441821,0.46593857545501993,0.0,0.030099023000826786,0.5587188122531913,0.43098177675712246,0.28989499879808245,0.4435023795753381,0.4366203163100947,0.0,0.5060040770307269,0.11621821150048195,0.2587888940592187,0.6671229125109692,0.5583503443196874,0.5203269452792993,0.01962060448419245,0.626260848194982,0.33364478067757,0.0,0.4218032515465502,0.39289499478647094,0.33822390766045274,0.8192444011258739,0.45220655298295775,0.45848915368470866,0.2699344781773183,0.38859631598442923,0.5340142054038644,0.5326268030320507,0.4189523219752802,0.2928008138272926,0.42155680669010076,0.782526664007289,0.0,0.16383227583528248,0.5424565717494054,0.3757959301793129,0.1895009668369153,0.20869329305600037,0.45718236110899746,0.6218296835275325,0.43759238924421806,0.31257552334112815,0.31092704155262474,0.7120873555663083,0.4903601921545143,0.0,0.3225649604018651,0.28244301850501174,0.30024455363797287,0.5784586108998364,0.4797662857082139,0.0,0.43415995493910475,0.6273976382292401,0.394032738673215,0.6430927504697013,0.09644556762008327,0.2555562059336266,0.6048549909933673,0.4159409573844677,0.6573287232265774,0.0,0.19234003343767958,0.30248364274736594,0.4619100562911236,0.5162317468062099,0.3284956875437921,0.38054271770789305,0.31752367088807976,0.397907090283238,0.5588062650319363,0.6130166721144117,0.5490950364518072,0.38958460518678784,0.4702475546578775,0.28652647187663927,0.596852915618404,0.7913931049688324,0.06105242928880117,0.4872978401198428,0.045447323355697566,0.580324667898356,0.4425549627163734,0.42577987475720536,0.462795744375496,0.4096023994801494,0.49682884324059384,0.5261126420328749,0.6968530258665642,0.366866948998792,0.4630085942912522,0.6002826430321578,0.14537116208419498,0.5826673000250405,0.6691097213101822,0.10477220317828984,0.4513737345559552,0.5146621118544314,0.0,0.24613362837194686,0.36065334360772494,0.36158074726902667,0.6421917862533288,0.24775006460000493,0.27127336377323785,0.5578666618861285,0.3915859201207287,0.3572787343021775,0.3792393287537442,0.42727432378209906,0.4297534459494824,0.19654456675666643,0.4293971654491434,0.3000281521211885,0.3839887817757234,0.4915323725854085,0.43978130264705906,0.12186784495013425,0.4857586930868928,0.0,0.7037670715731645,0.3413760121523599,0.35194665691604876,0.3814810945228405,0.440310372813991,0.05064199064053265,0.38798350384718117,0.4487406037564413,0.32222474968395887,0.4236009449492383,0.3878920833536871,0.6870500635443327,0.2604734641969405,0.3486938481309263,0.0,0.20869329305600037,0.2625236317988431,0.6664089136986546,0.307973540200851,0.0,0.2486231972265428,0.3241832534840192,0.3963499973357415,0.5575466070544313,0.8153094234481169,0.41405981866003005,0.6553374279566728,0.3015918842197499,0.5218041164020444,0.10878391943321775,0.3164018254726061,0.4659600564505383,0.3453508338801118,0.3146248959625221,0.32222474968395887,0.45642154284893144,0.6245192850618233,0.4030959330235405,0.4435629195993416,0.724056639616649,0.43272580468348376,0.11621821150048195,0.5209128916748071,0.5142994786214372,0.4283482228301815,0.2047018099741601,0.45718236110899746,0.2117626700593399,0.3942563634230579,0.04226200575442174,0.4016091761097351,0.2687414924836097,0.4618629757578804,0.11146570195835526,0.43145808715091494,0.8096309963367014,0.20628242340003344,0.5224885359178247,0.3369461078522318,0.7048693173624454,0.6584043498223027,0.16229257262777164,0.43628673242080296,0.46825098057731274,0.34441870106873007,0.438257628003624,0.5885403849770352,0.30708201910120514,0.31706398776672673,0.3856413652299444,0.16383227583528248,0.307973540200851,0.18201265025021707,0.44009192505039607,0.8382768155809268,0.23202403065879462,0.4534771377060711,0.3871027615917967,0.13914724411212054,0.34384791766038014,0.19026953513182987,0.3523847746182299,0.5004883163595654,0.5621381046657621,0.1444537851540595,0.28683655413466613,0.32066485315684623,0.6544395513198918,0.37450812494776187,0.2034496114024532,0.287267085473226,0.3192630723256925,0.3368185227871191,0.46736713708408417,0.39306493928820607,0.0,0.7495998976502942,0.020103107108688456,0.5372945646582652,0.704111070479773,0.31928088848131353,0.20780440355180985,0.571211989984027,0.3772195327201706,0.8229030633666199,0.5012473810443843,0.33396682297214064,0.2587888940592187,0.5373859622418391,0.8407976172096453,0.5111386038715922,0.4797222462610632,0.45495685714922096,0.48488436049453054,0.07672353637854812,0.5328647139363699,0.6899235790623204,0.0,0.5867902050299001,0.21855179634449917,0.4449172510015892,0.7658094339053032,0.5076676322509164,0.025225544503289288,0.796432796785156,0.34664073595193734,0.5289399869987347,0.45096152183198435,0.5330143503225715,0.29344035499114984,0.0,0.0,0.0,0.5975779475656142,0.6474982044153408,0.5359103273101933,0.2587888940592187,0.521436375398716,0.4016091761097351,0.5986825940680163,0.3369461078522318,0.7760063479291248,0.3011358039192318,0.311879770365313,0.5187918707538988,0.13914724411212054,0.318777386405667,0.42352661273709846,0.4695405067503955,0.5843083664590896,0.3888589535482848,0.0804863130050969,0.32949342079100896,0.6090309652814558,0.6182151847597421,0.13023233472690932,0.8689395286895706,0.3195875440556767,0.21443541720877624,0.32292172349465853,0.49815519994253865,0.413745928781042,0.44207760588800016,0.0,0.5193916566314982,0.514215080077012,0.4261707384997222,0.2707929498231365,0.3418602360765406,0.29032498490982217,0.40361909047023603,0.3279549500681772,0.5307887056123135,0.2603628897465896,0.395996846638219,0.6487230202817227,0.30971265959478744,0.4971712658491857,0.0,0.3369461078522318,0.40089020680646037,0.0814781688629378,0.3859780034749438,0.0,0.0,0.3667666392115102,0.7244541212143862,0.7696038955229214,0.2136605936834748,0.6484866678568533,0.1419310866904573,0.6631759543085954,0.5408240825574877,0.3879109873347374,0.5903523668008224,0.46307678783159933,0.0,0.05313965512693086,0.3707901849260187,0.5407693067121087,0.5502674196504533,0.0576991377488314,0.30573664121521904,0.019549086168488383,0.41689223584127355,0.4825626798679016,0.6641076769986378,0.7219098006483919,0.7504218706083665,0.5220250272479774,0.3432090250204166,0.25574516262532576,0.3788149814340116,0.5777062677055953,0.28588432173476763,0.4125323862621495,0.37583061820583563,0.49635724421752603,0.4854370938045729,0.6399121136752788,0.12646829619665623,0.27140320107467975,0.4739917150052736,0.25946125787438934,0.3432090250204166,0.6433448032045511,0.49533064520796755,0.7079029561575103,0.33364478067757,0.41048306456060135,0.5800025354290326,0.5019676606911927,0.4892955608455444,0.511278968654783,0.3907364012910779,0.5234948761199645,0.3517724117477209,0.11621821150048195,0.5218461546742207,0.4659600564505383,0.34790363527506407,0.19734481584037766,0.713799099848352,0.38003765413263024,0.34664073595193734,0.30193087449195544,0.40036958186211025,0.39184860473276395,0.4005125412889352,0.2773187487514397,0.0,0.0728129244947241,0.6339927426767611,0.3996628003650836,0.6082402575100521,0.46722103432839146,0.4167946028926135,0.6408644010576626,0.6311966721015305,0.3062098888512429,0.5331599224578503,0.4025422086922038,0.4898354928892952,0.7562618128524832,0.48507695318407607,0.0,0.5074531402285627,0.7638595222978392,0.6038802037383013,0.7222070623524683,0.38656421581106526,0.4025500300560141,0.0,0.3991640474127246,0.2369453709051733,0.3192630723256925,0.47295598761679125,0.3543916130259782,0.3587483065547793,0.3863742016122227,0.1255880286524168,0.0,0.6473805516387607,0.2846815238487418,0.250665204411602,0.2695705093330554,0.3833219971626033,0.7283477426687179,0.03422951971100352,0.24360508871071784,0.41908360496078056,0.581024082261102,0.6183740049667017,0.39289499478647094,0.24532884358913898,0.29640680879474,0.0,0.6110186251486782,0.3965854160712322,0.3444894872200899,0.2034496114024532,0.6577900484906738,0.6698030007259652,0.5422291410202636,0.3378649775924264,0.3650541739655404,0.33758374600848373,0.23729243310901027,0.34664073595193734,0.3139863999447645,0.7662495192787611,0.6824159094695972,0.3713361969351042,0.511367249163085,0.27286358409791445,0.43687476808561887,0.31040377110066464,0.0,0.13053626449231925,0.31084545275498265,0.7423783073643317,0.48392854110518924,0.6244146011772158,0.4697854275253076,0.5583289838826827,0.7101994874318178,0.34390572172247325,0.621128037674044,0.3230008139994218,0.0036196979702772802,0.28520881592153957,0.3229304979581785,0.4343833888662152,0.45870290072200925,0.49440339235067454,0.6088615271385631,0.2015366698384572,0.6753039290949983,0.45254381118610854,0.0,0.2590054243422979,0.6944332767728594,0.44683519525600557,0.7947692196079718,0.2370331399876623,0.0,0.31280895843756007,0.38083920871896215,0.41090586247665095,0.46722103432839146,0.5559650204867327,0.7070046434134489,0.2719484171521688,0.5544388639136875,0.29344035499114984,0.3732456887868021,0.7288581726422002,0.39574888172252576,0.2683681807465107,0.6324389209933323,0.42750490268791175,0.584976655348155,0.48450882331715484,0.4595632208390329,0.3432090250204166,0.6939175225403478,0.6230328257097114,0.5199620045785629,0.002590892575257908,0.1419310866904573,0.1544754778071079,0.7524241263784349,0.7320500990952303,0.5654418573611455,0.5323721666242032,0.1744340494734824,0.4907068573120664,0.3141602443801127,0.3571832498149451,0.7621398536802598,0.3968157387749094,0.23357812183821092,0.3637388369653486,0.4539745465752496,0.5236017284712902,0.5138366335552118,0.48284761645161134,0.2829741040591264,0.12646829619665623,0.6621979895170511,0.16383227583528248,0.4057958093888334,0.5901720468803853,0.47975609485825166,0.31928088848131353,0.02395925569434121,0.4828428240179383,0.27104244808099387,0.38549257170340767,0.0,0.36585561469556527,0.36261848284387277,0.6556855279203727,0.5669135856838796,0.5324571921888792,0.5262128378139506,0.6042108054383037,0.5991807696517805,0.5695348295152692,0.0,0.7036500624899747,0.3694525027687853,0.6049891074114021,0.3075412850332335,0.21907646229888678,0.220474378390216,0.5348226207489168,0.31931559059510217,0.7795962855901261,0.18665991626855227,0.4595632208390329,0.3390189026657384,0.5549929699403738,0.6621580985040199,0.6420211904173218,0.302398478158321,0.26097697111644147,0.4839297133881679,0.5542170070300378,0.6378078271426482,0.6059315844635635,0.7158352494390154,0.12741992401463698,0.6657773927924662,0.014042273322152465,0.3944532442377441,0.0,0.3585298120532113,0.2120021793151633,0.5232886515439205,0.32828922757867585,0.14912292196340138,0.3515990394500266,0.47295598761679125,0.3760618130816181,0.28851718334749554,0.7099650763857295,0.4104975594987442,0.31431225374035054,0.5352404104883052,0.23661875754705952,0.2526158036153937,0.5662070339742704,0.2868554877592293,0.01962060448419245,0.725582942263068,0.3667666392115102,0.10216771413614723,0.556987073654708,0.5014973834858234,0.33008420901432933,0.4524249943415104,0.4236012437597412,0.3199536574744053,0.6349761454631584,0.6799832848717987,0.44399611988259224,0.5468939794116625,0.397907090283238,0.46501529621314286,0.397907090283238,0.31928088848131353,0.5703764920619449,0.26565038758812887,0.5071461665405297,0.4357139911933503,0.003121298369468062,0.6102550657919543,0.4193454398638409,0.4455087183994092,0.0,0.5276791250374102,0.5000008547789663,0.12646829619665623,0.0,0.28880788514208633,0.12036325754073463,0.20539504940109954,0.5448775282525657,0.6999121264439769,0.5302810809905963,0.5959651258946541,0.6407865899990179,0.32630138806804065,0.04923055396517728,0.42041062969941145,0.42231317110827027,0.5160679655381422,0.3256468403379189,0.7191313783437678,0.40595362207787977,0.15161726847221557,0.6510207154080705,0.030066809762104074,0.10314523463395675,0.2557584683045252,0.19047728846389067,0.6934688546057677,0.5836452464179741,0.4349369763605636,0.37616915020974095,4.6591582469379667E-4,0.4387575530531068,0.027108362759763693,0.5744939400496374,0.281060331201476,0.1007517318837754,0.22352576311297123,0.4010024414978929,0.6570263907285293,0.07566411879070911,0.43665405617202724,0.0,0.7207084761747962,0.361499870652888,0.44958845268806913,0.35426804905355036,0.2564319623941328,0.7192379490112057,0.6372617429625445,0.3883511368521614,0.25987157670281547,0.0,0.4097826489912314,0.30573664121521904,0.5264865933777904,0.397907090283238,0.2634840828167587,0.5626069204302353,0.314639315522122,0.44450024100270924,0.8123681140171005,0.22014432998277833,0.6896433694923727,0.4046840321615103,0.7523294795796522,0.45237785720819845,0.4510259365352023,0.565030762844791,0.5090960173374319,0.5886895941960059,0.458339281784529,0.40361909047023603,0.3062590348550086,0.4614294118932193,0.3238265539334684,0.5480658966608933,0.2464577910229966,0.37503130058565015,0.0,0.39809588901147686,0.0,0.43036562161606595,0.5937819471542605,0.5067768473611503,0.1953718944973417,0.5849145253282471,0.49499681809946416,0.0,0.36447909410440105,0.5736848386494585,0.0,0.5356250633850663,0.4890452763966886,0.7724300093442356,0.2204551945457709,0.5778224606855052,0.0,0.6788792751930945,0.3879526647601961,0.0,0.48128374663785145,0.584756713730171,0.05246635243470976,0.21516462146260296,0.12646829619665623,0.48144540596161123,0.10878391943321775,0.3501588715905187,0.761180755816503,0.7840208320682784,0.2434184287344051,0.30841948469474956,0.3098177698055351,0.7246280421637609,0.6166988675984539,0.551931166381685,0.39664287586463587,0.4994201845005066,0.7174557307086269,0.2461635624422267,0.44384159406006674,0.5394616410745764,0.0028677249604741606,0.3518863516296503,0.15160634641496518,0.307973540200851,0.22923187910248222,0.7731645487573725,0.30385595324857595,0.4534760876202787,0.0,0.5559030133788578,0.3369461078522318,0.617278359820584,0.5998426469096787,0.3785960623246245,0.5377797158109283,0.3304455201943124,0.5346708968710385,0.6440570438210729,0.3425854494627778,0.6545802026467996,0.39534614217900566,0.6946596958962201,0.3456502127939042,0.5741546223834264,0.3000281521211885,0.5588132798834317,0.7260370309689912,0.6828917478749896,0.2951488873753667,0.29942516082334847,0.33728709456229244,0.3327543521584052,0.397907090283238,0.5760652424984127,0.5507941748073304,0.5143223152531918,0.5063440283333434,0.6289646496618333,0.29771965982115844,0.3248869618208131,0.47567574761415954,0.408517388812911,0.5686947476686613,0.5923673070084063,0.18040464440945914,0.2606794070012417,0.11258136252710926,0.5132518900328683,0.42931739497443777,0.7664804669838959,0.5151863726022239,0.0881792129921165,0.303613742827598,0.34664073595193734,0.4634004689306044};
        List<Double> expectedOutlierScores = Arrays.stream(expectedDoubleOutlierScores).boxed().collect(Collectors.toList());

        assertEquals(expectedClusterLabels, clusterLabels);
        assertEquals(expectedOutlierScores, outlierScores);
    }

    @Test
    public void testEndToEndPredictWithCSVData() throws URISyntaxException {
        ClusteringFactory clusteringFactory = new ClusteringFactory();
        ResponseProcessor<ClusterID> emptyResponseProcessor = new EmptyResponseProcessor<>(clusteringFactory);
        Map<String, FieldProcessor> regexMappingProcessors = new HashMap<>();
        regexMappingProcessors.put("Feature1", new DoubleFieldProcessor("Feature1"));
        regexMappingProcessors.put("Feature2", new DoubleFieldProcessor("Feature2"));
        regexMappingProcessors.put("Feature3", new DoubleFieldProcessor("Feature3"));
        RowProcessor<ClusterID> rowProcessor = new RowProcessor<>(emptyResponseProcessor,regexMappingProcessors);

        URI trainData = this.getClass().getResource("/basic-gaussians-train.csv").toURI();
        CSVDataSource<ClusterID> csvDataSource = new CSVDataSource<>(Paths.get(trainData),rowProcessor,false);
        Dataset<ClusterID> dataset = new MutableDataset<>(csvDataSource);

        URI predictData = this.getClass().getResource("/basic-gaussians-predict.csv").toURI();
        CSVDataSource<ClusterID> csvTestSource = new CSVDataSource<>(Paths.get(predictData),rowProcessor,false);
        Dataset<ClusterID> testSet = new MutableDataset<>(csvTestSource);

        HdbscanTrainer trainer = new HdbscanTrainer(7, DistanceType.L2.getDistance(), 7,1, NeighboursQueryFactoryType.BRUTE_FORCE);
        HdbscanModel model = trainer.train(dataset);

        List<Integer> clusterLabels = model.getClusterLabels();
        List<Double> outlierScores = model.getOutlierScores();

        int [] expectedIntClusterLabels = {3,5,4,5,0,3,4,4,5,3,4,5,5,5,3,5,4,5,5,5,5,0,5,5,5,5,0,5,4,0,3,3,4,5,3,5,5,3,5,4,3,5,5,5,3,3,3,3,3,3,5,5,4,5,4,5,3,5,4,5,4,0,4,4,5,5,4,5,4,4,5,5,3,3,4,5,3,5,5,3,5,5,5,4,3,4,5,5,3,3,4,5,4,4,5,5,3,3,5,5,4,4,5,4,5,5,4,5,3,3,4,3,5,3,3,4,4,3,5,4,5,3,3,5,5,3,4,4,3,5,5,0,3,5,4,3,5,5,3,4,4,5,4,4,5,3,5,3,4,5,3,5,5,3,5,5,3,4,4,4,3,3,4,4,5,5,5,5,3,5,3,5,5,3,5,3,5,5,5,3,5,5,5,5,4,4,4,5,5,4,5,0,5,3,5,5,3,4,4,4,5,4,3,5,5,5,4,5,4,5,5,3,5,4,5,5,5,4,3,3,3,5,5,5,5,3,5,4,5,4,3,5,4,5,5,0,3,3,5,3,3,0,3,5,5,0,4,5,0,5,5,5,5,3,3,5,0,3,5,3,5,4,4,5,5,5,4,5,4,5,5,5,3,5,5,4,4,4,4,4,4,5,5,3,5,5,3,5,4,5,5,5,4,4,4,3,4,3,5,3,5,3,4,4,4,3,4,5,4,5,5,4,3,4,4,4,3,5,3,5,4,5,5,3,5,5,3,3,3,0,4,3,4,5,4,5,3,5,4,3,0,3,5,3,5,4,4,5,0,4,3,5,4,0,5,4,4,3,4,3,3,5,5,5,5,3,5,3,4,4,4,4,3,4,3,5,3,5,3,3,5,3,5,5,5,3,4,5,3,5,4,5,5,5,5,5,4,5,3,4,3,3,5,5,5,4,5,4,5,5,5,5,4,5,5,5,4,5,3,5,3,5,0,3,3,5,3,4,5,5,5,5,3,4,3,3,0,5,5,0,3,5,5,5,5,3,5,5,3,5,5,5,5,5,4,4,5,4,5,5,0,5,5,3,3,3,5,3,0,5,3,5,5,4,5,5,0,5,5,5,5,3,5,5,5,4,3,5,4,4,4,5,5,5,4,5,5,4,5,3,5,4,4,4,3,3,5,5,3,4,4,5,5,3,5,3,5,4,5,4,3,3,5,3,5,3,3,3,4,3,4,5,5,5,4,4,4,5,5,4,3,4,5,4,5,3,5,0,5,4,5,4,5,5,5,4,4,5,3,4,3,5,5,5,3,5,5,3,5,3,5,4,4,4,5,5,5,4,3,5,5,3,3,5,3,5,4,3,4,5,5,5,5,5,5,3,4,4,4,5,5,5,3,5,5,5,3,3,3,5,3,5,5,4,4,4,4,5,5,5,5,5,4,3,5,3,5,0,3,5,5,5,3,5,5,4,0,4,0,3,5,5,3,3,5,5,3,3,5,5,4,3,3,5,5,5,5,3,5,5,5,4,5,4,5,5,3,3,4,5,3,4,5,5,5,5,5,5,5,5,5,3,5,4,5,4,5,0,5,5,4,5,4,4,3,5,3,4,3,3,5,3,3,5,4,5,5,5,5,4,0,3,3,4,4,3,5,4,3,3,4,5,5,4,3,4,5,4,5,5,5,4,5,3,3,3,4,4,4,3,4,5,5,5,3,5,3,5,5,4,3,3,5,4,5,3,3,5,4,3,3,5,4,5,5,4,5,4,5,3,3,5,5,5,0,5,3,4,3,5,4,5,5,5,5,5,5,5,4,4,5,3,0,5,4,4,4,5,5,5,3,5,5,5,4,5,4,5,5,5,5,5,0,5,5,3,3,5,3,4,5,3,4,4,5,3,5,5,3,5,3,5,5,5,5,3,4,3,3,5,3,4,4,3,5,4,5,5,4,4,3,4,5,5,4,5,3,5,3,4,3,5,0,4,4,4,5,4,5,4,3,5,3,0,4,4,5,5,5,3,4,3,5,5,3,3,3,4,5,5,5,3,4,5,0,4,5,5,3,5,3,0,3,5,4,5,5,4,5,5,5,5,5,4,4,4,3,4,5,4,5,4,5,4,4,4,3,4,5,4,5,3,5,5,3,4,5,5,5,5,4,5,3,3,3,3,5,4,5,5,5,3,5,3,5,5,5,3,4,5,5,5,5,5,4,5,5,5,3,0,5,3,3,5,5,3,5,5,4,3,3,3,3,0,3,4,5,3,4,5,5,4,5,3,3,3,5,5,3,4,3,5,4,5,5,5,3,5,3,5,5,5,5,5,5,4,3,5,3,3,4,5,5,4,4,3,5,4,5,4,5,5,5,5,5,3,3,0,5,3,5,4,5,5,5,5,3,5,5,3,5,4,4,5,3,5,4,3,4,5,3,5,5,4,3,5,3,3,5,5,5,3,3,3,5,5,5,3,4,5,5,5,5,5,5,5,4,5,3,5,4,3,3,3,5,5,5,5,4,5,4,5,4,5,4,3,5,0,5,5,0,4,5,5,4,3,5,3,4,5,3,5,5,5,3,5,5,5,4,5,5,3,3,5,5,5,5,4,5,4,5,3,4,5,4,5,5,0,5,4,5,3,3,4,5,3,5,5,5,3,4,3,4,3,4,4,5,3,5,5,0,3,4,3,5,5,4,5,5,4,5,3,5,3,5,5,3,5,3,4,5,5,3,5,4,5,5,5,4,4,5,5,5,3,4,3,5,4,4,5,5,5,3,3,5,4,5,5,3,3,5,4,5,4,4,4,3,3,3,5,3,3,3,5,3,5,5,5,4,5,5,3,4,3,3,3,5,3,5,4,4,5,3,0,5,3,3,5,5,4,5,3,4,4,5,5,4,4,5,3,4,4,5,5,5,5,3,5,3,3,5,5,3,5,5,3,3,3,5,5,4,3,5,4,4,3,5,5,3,0,4,4,4,3,4,5,5,5,5,3,5,3,5,3,5,4,5,3,4,3,5,5,5,5,4,3,5,5,3,5,5,4,4,5,3,5,3,5,4,3,5,5,5,5,4,4,3,5,4,5,5,5,5,5,5,3,5,4,5,5,4,5,3,4,4,5,3,4,5,5,5,3,4,4,4,5,5,4,5,3,3,4,5,3,5,5,4,5,5,5,4,5,5,3,4,5,5,0,4,4,3,0,5,5,4,4,5,5,4,5,5,4,3,4,3,5,0,3,5,4,5,3,3,5,4,3,5,5,5,4,5,3,5,5,5,4,5,5,0,5,5,5,4,3,4,5,0,5,5,3,5,0,5,5,5,5,5,5,4,3,5,3,4,0,5,5,0,5,5,3,5,5,3,5,5,5,5,4,3,3,5,4,3,3,3,5,5,5,5,4,3,3,5,5,5,3,5,3,3,4,5,5,5,4,5,5,5,5,5,5,5,5,4,5,3,5,5,4,5,5,4,3,5,5,5,5,5,4,5,0,5,3,5,3,3,5,5,4,5,5,5,5,4,5,4,5,5,4,5,5,0,4,5,5,4,4,5,5,5,5,4,5,5,5,3,5,5,5,4,5,4,4,5,4,4,4,5,4,3,3,3,4,3,5,4,3,5,5,3,3,5,3,4,3,5,5,5,5,3,5,5,3,5,4,3,0,5,4,4,3,5,4,4,3,5,4,5,5,5,4,3,4,5,5,4,3,3,5,5,5,5,5,5,3,5,3,5,5,4,4,5,5,3,5,5,5,5,5,5,3,5,3,0,5,3,3,5,5,5,5,3,3,4,3,4,5,5,3,5,4,5,4,3,3,4,5,5,3,5,4,3,5,3,3,4,0,5,5,5,4,4,5,3,3,5,5,5,5,5,5,3,5,5,5,4,4,5,5,5,3,5,5,3,0,4,4,3,4,4,4,5,0,5,3,5,5,4,5,5,3,5,4,3,5,5,5,4,4,5,5,5,5,3,5,4,4,5,4,5,5,5,3,4,3,5,5,4,5,4,4,0,4,4,4,4,4,3,5,3,5,4,5,4,4,3,3,3,5,5,5,5,5,3,5,3,5,4,5,4,4,4,3,3,3,3,5,5,5,4,3,5,3,5,3,4,5,5,5,4,5,3,3,3,4,3,3,5,4,5,3,5,3,5,5,3,5,3,5,3,4,4,4,3,5,5,5,3,4,4,3,5,3,4,4,4,4,5,3,5,5,4,5,5,5,5,3,5,5,5,4,3,4,4,5,4,4,3,5,5,5,5,3,5,5,5,4,4,3,3,3,5,4,3,0,4,4,5,0,5,5,3,3,4,5,4,5,3,3,5,4,5,5,3,5,4,5,5,5,5,4,4,5,5,5,5,5,0,3,4,5,4,4,5,3,4,5,5,5,3,3,3,0,0,3,3,5,3,3,5,5,3,5,5,5,4,5,4,3,4,3,0,3,5,4,4,3,5,4,4,4,3,5,5,3,4,4,3,3,4,5,4,3,3,3,4,5,3,3,4,4};
        List<Integer> expectedClusterLabels = Arrays.stream(expectedIntClusterLabels).boxed().collect(Collectors.toList());

        double [] expectedDoubleOutlierScores = {0.47358175271351555,0.5414658310482977,0.303890489654853,0.4280760238473448,0.7483901760069853,0.3601622156931149,0.5171162528208143,0.5158094327168141,0.636222606790072,0.3311761021443682,0.40952597476825736,0.04620516071879277,0.0804863130050969,0.36782631972078605,0.2695742331327128,0.43552883184782476,0.42700004946312253,0.37935517113968176,0.6449092021603602,0.5676065051695158,0.4483291690445501,0.7681177752921566,0.0,0.21731496412888562,0.581117423864291,0.6308335986889171,0.7797114008784585,0.3003135504775737,0.5948303165065607,0.7514669137325711,0.16871756538011295,0.6224928359010734,0.5197457487326744,0.0,0.31306681440424333,0.3812638737290107,0.5255720233717707,0.4112747353567219,0.47509756458767316,0.6041924608911899,0.6170543537831388,0.3535120791216183,0.0,0.5034420938549125,0.28989499879808245,0.29224627768607514,0.0,0.3375415399055758,0.11621821150048195,0.32681227425828385,0.40827088653349086,0.38891555341987816,0.28048608629431215,0.14912292196340138,0.7379881716067582,0.32546418038027936,0.4055250865928418,0.0,0.44231927827339534,0.4681005824053899,0.6469896913759335,0.7735686795935826,0.6172083079631403,0.598596616061936,0.07672353637854812,0.0,0.5288834031904994,0.6481435074684916,0.47955598689448287,0.37392947785498154,0.653648938906807,0.0,0.5895947175711314,0.36599358407440996,0.6151352352735302,0.5187753107469597,0.5826702556968544,0.6444693945436082,0.27236826028499506,0.0,0.41562294571396974,0.5977023632181397,0.5096592353353864,0.2542120810315135,0.16871756538011295,0.4630698336866913,0.5936321631410117,0.21516462146260296,0.0,0.737055324600702,0.6052905517563147,0.22732561863527845,0.29187996523259463,0.42700004946312253,0.47971852678268034,0.0,0.4112747353567219,0.3409635687892707,0.47381866965726305,0.30376928888062393,0.574518118431571,0.42683510626039356,0.5966674138239424,0.36283412531215453,0.3990832100389875,0.12154778462865656,0.32323624241071935,0.0,0.3456502127939042,0.0,0.35458090179260204,0.4962345880567618,0.42361379464816384,0.5390727342131265,0.2796421977643141,0.37037659174738524,0.0,0.5841840456402354,0.0,0.4464356339089496,0.29945586899686516,0.0,0.7060160641811467,0.2369453709051733,0.06492324355125823,0.3861896255681202,0.5460893502772224,0.0,0.7222130100294228,0.32446676707111055,0.4357740061945765,0.836897085559128,0.446397883570942,0.25435336247371376,0.5671275222481266,0.3456502127939042,0.16699586735690297,0.500191890833944,0.20836641600896022,0.6225283247269507,0.3531562617933499,0.4324013942368624,0.5905001969941427,0.3739583648911464,0.39335742422941844,0.47698006683148797,0.26418664607144837,0.4071448942368182,0.5124823512443748,0.4185983644477421,0.5594270332986124,0.6230867835968079,0.37496236017491336,0.7555429921879805,0.6699942010322993,0.5127286468158467,0.22923187910248222,0.6195521968425128,0.06105242928880117,0.4493840155738392,0.2948004212500368,0.2727987081884128,0.3662323752301081,0.2908145178310457,0.7220745542200588,0.19092041195838683,0.3432090250204166,0.2063486508048732,0.013925122169310966,0.0,0.0,0.0,0.06492324355125823,0.44426589083652057,0.44398591628262796,0.37891294036812484,0.7156836869466953,0.0,0.2815040444723871,0.31197985827951213,0.2891995980313147,0.5512983085307032,0.31421939280536004,0.4377058742150195,0.5728743730931138,0.49115216642194415,0.0,0.43828168695823744,0.41685484146125196,0.36965152735510665,0.26732125164117826,0.7721012392234178,0.4583041966983865,0.44456048652206126,0.3741683513565959,0.533346187911755,0.7587434939764999,0.29402930070408473,0.4144242793470112,0.7295001072990965,0.5713041005281074,0.6327900368481001,0.5933533497269812,0.5956793667033696,0.6517825205768181,0.5429686245606076,0.39486737535967487,0.3265855728027738,0.5221989530382277,0.5310138807891505,0.0,0.45609070594174217,0.6593186724760913,0.38933121457385034,0.7135260731909046,0.0,0.4924356904948839,0.31770792442784535,0.5933853373609538,0.3748651677610172,0.6254229089345361,0.39597398385394467,0.008171288900179485,0.1496330958893356,0.32925122056086287,0.40381249866163804,0.04799339719711404,0.43971502933032214,0.6043492843608917,0.3927362032738918,0.26097697111644147,0.21516462146260296,0.6119597899031086,0.48193784898644665,0.5334068997107364,0.8286024733733925,0.5296135420884414,0.5110852514237674,0.5469021659826454,0.3456502127939042,0.5386953819112004,0.7736556773783174,0.23482365778563496,0.4424763817633829,0.7150819204214296,0.7485411645263464,0.0,0.4771358781074473,0.7435151574317422,0.29946053564660136,0.6042383596284573,0.461764258382828,0.14912292196340138,0.5149256672122535,0.6343721193118133,0.3917923406934356,0.803334914527963,0.28989499879808245,0.49037030144326954,0.7309622306419712,0.47137478106163877,0.30468532584859165,0.2724456879293514,0.30549132501511833,0.6408641989046773,0.3953913856557185,0.4107663612281326,0.2690894183464325,0.30306198384729377,0.43415995493910475,0.523204580638497,0.6990082287262445,0.5878240106699939,0.4816621654331692,0.6445108484123541,0.22860598417243572,0.5378609089924106,0.23044355932635463,0.4886778772544713,0.45226951791230086,0.5160370289393739,0.6505650981040596,0.701466874912067,0.42689743788477885,0.5396433274683845,0.4776041796757132,0.3310780648601609,0.31648418053759364,0.6034734047450258,0.3986352885793346,0.0,0.6458854232442651,0.39146505078831206,0.6172539393496476,0.030066809762104074,0.3493040196609468,0.6478747619463716,0.3456502127939042,0.3535496611554798,0.2207349697015366,0.6154008035515187,0.6045076456433015,0.532794242259455,0.710877510632483,0.4367505281349391,0.4455087183994092,0.6942377059292528,0.34174552110905276,0.6585122756004673,0.3284956875437921,0.42002499215129263,0.3634134700766245,0.3687581876367665,0.4323042387892171,0.2832845410928383,0.2998248478647869,0.23729243310901027,0.21516462146260296,0.1980858670864919,0.3365306429058218,0.23383238629341863,0.39484971592847373,0.6576646032648548,0.5479046532061724,0.2967447898021014,0.3418391400708265,0.3839887817757234,0.3519283734067741,0.22923187910248222,0.7958314367109036,0.48624013180148806,0.38225496965262873,0.5292441167344578,0.48761908580442936,0.6341566680363746,0.30662140654113357,0.21855179634449917,0.4931293566573668,0.5692830203404516,0.0,0.7800388801537237,0.3624204074542483,0.31895384630103774,0.7594189772964117,0.5695348295152692,0.3531562617933499,0.40354222391518924,0.5569180416682643,0.7728743002601586,0.2801336008369837,0.48633934197199924,0.34174552110905276,0.704918165207694,0.7850772032362556,0.2283896005703272,0.38091982010388936,0.4833036899911439,0.464691645899445,0.35209077660061894,0.0,0.3839887817757234,0.36305367292219415,0.3741683513565959,0.5084896108482566,0.16575812059028605,0.4225951359081882,0.3143792517940033,0.5067429952592745,0.0487514432337689,0.6598081915185929,0.41574270598151686,0.4216974462784284,0.5416206409141738,0.30464987786622577,0.12741992401463698,0.5822141614023605,0.6055550272678605,0.5776422244603738,0.4970267038737336,0.13023233472690932,0.3284956875437921,0.3233928479834631,0.592266021893906,0.3984040787215949,0.506638357473808,0.5317723301954207,0.21476582938139688,0.3526660020106209,0.029347971609487877,0.2999535725433774,0.0,0.469887053155719,0.670226977385818,0.3672668668575686,0.5015555056496628,0.4085857346589076,0.440764574237398,0.0,0.5105400540069525,0.43014535060684056,0.3272310658291241,0.3369461078522318,0.02773285125509206,0.5417179683725725,0.0576991377488314,0.24036574951634482,0.0,0.4539839805777919,0.26921794560895074,0.3195633140487657,0.3873683640266503,0.3082926292203588,0.5451295040181344,0.5057154073499082,0.4765447223291741,0.5845098021058535,0.0,0.2738860944950706,0.4324679970998656,0.31211705980815607,0.6347908457930689,0.18525063623712357,0.7751036310404359,0.26097697111644147,0.42106254339227944,0.5378064251110591,0.4873311828072008,0.684775745755401,0.3350175591159461,0.6199553903601905,0.35448733323678416,0.6063259139226185,0.690657312622633,0.366904341305906,0.3090329547500952,0.3874162195368408,0.7983767897437704,0.4678939719541557,0.5795563831019814,0.800125089204656,0.4089243362601419,0.6323003476130089,0.0,0.0,0.3765670404310496,0.006254727823924222,0.14912292196340138,0.7239915467402447,0.16871756538011295,0.4411338219017581,0.48221298536204915,0.2947832526838541,0.35513520468722715,0.3904290091452032,0.6318512482492376,0.46463510678700126,0.08877011102792942,0.5065869272889156,0.48213406880902177,0.0,0.8041467260207043,0.4922677742042706,0.6204902458719173,0.49515729128119745,0.825466290928847,0.0,0.37401373277278727,0.22371616934103422,0.7792051172641109,0.630656729728954,0.4494888079774554,0.0,0.4426781742253425,0.37607706270406815,0.13860627552095273,0.49750739084196827,0.7610952220826447,0.0,0.4963988970762506,0.6132440414398083,0.5737389221302394,0.3738471519240103,0.5187918707538988,0.6241655902326204,0.4595620492165915,0.2524934615614006,0.6051568335067139,0.6413296769660171,0.4194687379771409,0.0,0.5364737520165368,0.3712819238193623,0.6141956298831273,0.0,0.31091125696266664,0.1576637307821378,0.3249620517856061,0.3514800658116354,0.19245638188636915,0.37448424125384494,0.3647643364817389,0.07039767901958627,0.5724338763672463,0.6704571004283082,0.40800318903129196,0.5177181113022553,0.3580467970700235,0.08575367044706506,0.2778324875738022,0.3289614001236939,0.4143099499740214,0.6366964323474587,0.0,0.5105758746418961,0.0,0.5618372284748705,0.12646829619665623,0.6482714408442347,0.38767201120457384,0.5334741458564703,0.3601622156931149,0.250093797938734,0.4136198128134888,0.24125797661850068,0.27310212308386395,0.5416481617475357,0.4938300333019511,0.18967468982070068,0.6946183271611897,0.3089076300897101,0.672633721309082,0.402628639049357,0.35420966945200016,0.35768192154839074,0.7139614952900545,0.6702485953613595,0.6701806959433333,0.6845570018610234,0.48518484093582603,0.37037659174738524,0.7323044818001779,0.0,0.23619829064472764,0.48276024513568916,0.0,0.3021327855295476,0.39015721745013754,0.7502027616450202,0.24822768816123908,0.4011452989559052,0.23825296231784654,0.0,0.3923419763052197,0.4392727199165206,0.0,0.30464987786622577,0.29502794757113626,0.49046939602346395,0.38668912579614567,0.6306152451795839,0.16383227583528248,0.05246635243470976,0.1870139318759102,0.0,0.6415295074473144,0.20609843645540582,0.5164726440601963,0.8165507031399903,0.3449033588463204,0.570789604958164,0.39641599406810246,0.4835012526920641,0.0,0.41229428759934716,0.5168241717218262,0.16001248792274236,0.7070403531593957,0.316258371536396,0.5866866583181796,0.4842762987844166,0.1412447876793511,0.4885653007199101,0.17742171646445526,0.21128858246120308,0.7246425646330104,0.38054271770789305,0.41729533998718393,0.38837234138454346,0.7161530344197321,0.4050264383107697,0.0,0.4041395748236205,0.12646829619665623,0.4548048852493848,0.548358116752813,0.27201798024213364,0.5314728192768744,0.45668197454332626,0.40354222391518924,0.7124363075265328,0.38353143252244837,0.5056143775709685,0.3692367230351188,0.44661691862600406,0.036971755744779955,0.305372373671393,0.614649633720348,0.2358917191458988,0.35721696422529414,0.12373894351399051,0.2563532167091731,0.44661691862600406,0.5825394961236873,0.5415154389349499,0.29309949552087433,0.4058555057397688,0.6741774613981186,0.24471552753301118,0.7223516672072421,0.4520632835456354,0.35448733323678416,0.5966657123375374,0.4083408930635387,0.28289737773000867,0.5519815413081102,0.4005135049940618,0.4484716682058212,0.7882540776413052,0.4216063123159455,0.6088004746195586,0.44717928204495916,0.24345698942084792,0.27050449902435314,0.5389150357399828,0.533377433835126,0.5314728192768744,0.824862495936904,0.5183916166009674,0.7792989152589149,0.04923055396517728,0.3707483862540023,0.3837866626791563,0.38837816755874777,0.5478409953110283,0.3867611937625697,0.5103734383363709,0.400928574765699,0.45491551208332315,0.6779568069562565,0.5582109451011785,0.3245509517111206,0.4463959189823703,0.347680924801696,0.0,0.5796011947781625,0.49391109297595615,0.3168620178485899,0.3832014817548638,0.35495535150309865,0.04384108680937504,0.2690894183464325,0.37607706270406815,0.0,0.5078696067810057,0.4824138144675951,0.42906278112439844,0.4416371143081972,0.39961367734417963,0.6708600225497656,0.3000637654786039,0.19026953513182987,0.3120423326657491,0.271420089588442,0.5014305379452317,0.6230867835968079,0.3944532442377441,0.7124250069940696,0.4884249302908067,0.14912292196340138,0.4487406037564413,0.0,0.6753662651608616,0.3000281521211885,0.49919107135355445,0.5481353689825204,0.29309949552087433,0.2864707971738649,0.7455311556523028,0.35091553378068674,0.21343677258672245,0.5327488204099942,0.22525840601413705,0.6728062232751489,0.6659179224620204,0.7282095868644627,0.4672500162555244,0.7044288902098275,0.3326680098621956,0.3514654253195898,0.441662396411723,0.7147389215662775,0.3839887817757234,0.3587483065547793,0.44661691862600406,0.49549221349784567,0.48125433911380033,0.3874442098214338,0.12076619090264895,0.38335278693511876,0.399864395204778,0.7853119381870757,0.5815444881643806,0.60075814695453,0.0,0.0,0.13023233472690932,0.6337055987622278,0.38970077213081633,0.33546131400889667,0.2797406114384773,0.5570984019446698,0.33520713357537024,0.259432920934616,0.5778581756680433,0.2587888940592187,0.49263272542265113,0.2117626700593399,0.6514568566853232,0.6115633922928441,0.0,0.0,0.0,0.5056504922974333,0.3159504323824319,0.3839887817757234,0.21522091145386024,0.6889277295819016,0.4512497867954631,0.41340288827677096,0.5513101269971545,0.4653985663774486,0.18416820074811935,0.0,0.4721412633683266,0.5473388916214317,0.5034420938549125,0.16871756538011295,0.5380586828824034,0.4261492431702657,0.664431042784994,0.2464553365511717,0.36293632495112405,0.21516462146260296,0.29624145142172087,0.4812029699324305,0.4245745334470171,0.38967314869684866,0.320429067327754,0.29502794757113626,0.46192415366574313,0.44916053156133007,0.4114860008687803,0.33795614531013884,0.0,0.5976131758500893,0.4623395190754902,0.5481353689825204,0.6764439674169562,0.09663432889057066,0.7235452845604936,0.2153089051904491,0.45483309301099795,0.311879770365313,0.2176772660593751,0.7818871791689734,0.576036083086203,0.38214297023053034,0.6447113660606665,0.25870717242550656,0.6482171550650802,0.46744596704662944,0.0804863130050969,0.3568293291614032,0.3965854160712322,0.28381812710257803,0.3575686250517781,0.4483191693347306,0.3632190216549879,0.353496425734644,0.42344290047472666,0.4515581428863833,0.4830424925464114,0.750766842520767,0.57514269298302,0.4714411602933958,0.5742402198258162,0.3908007998268329,0.4178441209687199,0.0,0.3641789459960304,0.5795749487163394,0.6980648149582386,0.0576991377488314,0.24838525867789962,0.4539122529800673,0.6463117770001292,0.14038039185628248,0.39664287586463587,0.44661691862600406,0.5476880701644403,0.7240190537807336,0.5528073786295289,0.7797114008784585,0.0,0.5687397614212621,0.5943137988537931,0.44916053156133007,0.6108115751867618,0.48907914078946124,0.6152199519410408,0.311879770365313,0.48461733608036817,0.4472625052220116,0.4068457725528115,0.0,0.49231583580717664,0.5734180359260712,0.0,0.5210280192451475,0.5015794237659166,0.5489418048109322,0.6987557223641838,0.3634350826313635,0.4273940091825391,0.3571832498149451,0.2506644346627148,0.47482663268029757,0.3456502127939042,0.7218887249554182,0.48450901239195,0.30832139557613814,0.6942377059292528,0.5478338040166255,0.37926915278169526,0.4215795903281747,0.29187996523259463,0.5575466070544313,0.17128563838715205,0.0,0.4777880836232149,0.690986324522467,0.515644424542038,0.3071342895296215,0.39352470710923604,0.67055758222458,0.47000342590284294,0.3045511460387763,0.0912857343475364,0.6375303640190447,0.208244404119859,0.009895402151539168,0.3000281521211885,0.7433709674265416,0.35744576514628135,0.3028548915827576,0.2987972413853457,0.4689282144313608,0.6019980019631361,0.3227350807072843,0.5004621107752452,0.42202870044204677,0.0,0.6713959327679027,0.7919321267853209,0.0,0.38933121457385034,0.2433458258089689,0.04667067256282831,0.23825296231784654,0.6097343190385305,0.6063938955405117,0.05914335020781181,0.48195396363988063,0.424572298013397,0.6686853357882518,0.3636768327539607,0.5393272700296402,0.6000407196929238,0.0,0.48570902102061386,0.3167472811883112,0.40749409537327475,0.409272864751405,0.3634054954338538,0.7443129370757603,0.37357727102772265,0.20060074536146477,0.40607335773962094,0.23357812183821092,0.2789333781664347,0.3736073131529789,0.8211876828443099,0.5319171725741765,0.4902019105761406,0.49667899333384913,0.5591687404281019,0.46061538831786275,0.6078655545663287,0.09663432889057066,0.19979285689975457,0.5070473236774482,0.23210538458334418,0.5668952491122194,0.3193224998390394,0.021314157993151395,0.4296502240193436,0.8098565653475192,0.5610906350828531,0.20971226806420518,0.56523765147008,0.4249442221577012,0.0,0.3219878631993316,0.044397942146806146,0.23212096407894034,0.7374055447714696,0.5047651337189344,0.5960718597740056,0.45871233826373703,0.6776524931947915,0.6513736846165257,0.2810303170277002,0.22210950812220076,0.36096207094872057,0.4915045563950171,0.3621420038415023,0.5885902046751965,0.13095575420822192,0.573947987934874,0.10683699690904058,0.4706700159996964,0.391506587624198,0.28973699342477544,0.10098548496967541,0.3899902103207685,0.375489089425478,0.3079971578748303,0.35869536525682366,0.31902103206609844,0.5710708032211278,0.43101010639931325,0.35989838086301873,0.05064199064053265,0.3218065191758813,0.6228332825949527,0.3369989106364166,0.15156049125160376,0.4526726144485661,0.4995213902743789,0.4561785929208906,0.6837853978865358,0.5138215435240225,0.44555462770565135,0.0,0.5203998985860332,0.1914749242830559,0.4213720497040293,0.3944532442377441,0.4707048526334472,0.7756020483625485,0.32222474968395887,0.25546678830793745,0.10445970519304315,0.5699172346083162,0.3284956875437921,0.3885161545370044,0.02170033331990273,0.3396177586485829,0.4962476240007714,0.5190860744389649,0.3973405683869258,0.29906534000673657,0.4062740633691959,0.7645276133249075,0.3510955181077545,0.5814424052604774,0.6824557216441123,0.015150158490871979,0.5429938491377828,0.0,0.5153083371980647,0.044397942146806146,0.4223885221674304,0.3208648671839498,0.3426627732363028,0.3839887817757234,0.3898397248523402,0.36674442374867555,0.0,0.47487276535749223,0.2773187487514397,0.37408657262170364,0.6022516114053922,0.5308893639772336,0.0,0.18525063623712357,0.3640103014176189,0.5502403010859089,0.0764283212533079,0.32171751424416495,0.30662140654113357,0.5742984002662819,0.635575817965703,0.21430103027247993,0.5013206753014231,0.7433560350058463,0.6527316165124747,0.21024192708833367,0.6144510451972626,0.613713139729793,0.35917910678204135,0.4614150998565474,0.6132440414398083,0.4261021492590459,0.4839651073727408,0.3298591651956073,0.3209207612728636,0.5829059860049526,0.38409496468371396,0.6096325020762532,0.2947309863444706,0.271535884213859,0.47588027161081614,0.36528791684635475,0.0,0.5455788675271134,0.7459405573458152,0.7553482085712159,0.7065367439907762,0.4998307404683665,0.36440137993138655,0.5312628361779903,0.3494326940794764,0.4561785929208906,0.40748949841951376,0.46120107396619303,0.6240746889096774,0.5215154349365304,0.2815040444723871,0.37403414173311245,0.31175336804484455,0.3699210038991867,0.5192358059694571,0.0,0.24245916384716704,0.5037910091610112,0.36523994016712846,0.28989499879808245,0.44741858271285906,0.6300677079889229,0.1082558667450858,0.3474729280531976,0.0,0.6273966388025098,0.21855179634449917,0.48055504929674553,0.6134611454996968,0.5617371240784204,0.4943181931548606,0.5345139843278115,0.3432090250204166,0.3176357078316202,0.2951997178567569,0.46776604397675103,0.3910952366000655,0.6148956798317169,0.19580197732062377,0.5828730085168237,0.29309949552087433,0.2636664436319176,0.26015141405897024,0.45036530982824874,0.2791008840821435,0.34392296583963977,0.12646829619665623,0.32389994465562,0.6696145564139786,0.49750739084196827,0.26097697111644147,0.5932130316797035,0.4928544668900706,0.3309082318222377,0.5296146206392793,0.37871784869460057,0.6978733929881893,0.43031286194284957,0.0,0.42043689162825093,0.6850818403256127,0.33974383297301713,0.4695780241344999,0.4652473386946798,0.2908145178310457,0.3589050115424707,0.4353111887880863,0.4072598163286715,0.5459419400712915,0.7979176723383391,0.5493610496383468,0.44447754406386353,0.7682650664381584,0.1728466643533383,0.5518653792435592,0.3412864662457583,0.5933735423795428,0.3839887817757234,0.25323602320148264,0.6999080948452584,0.398331287995339,0.6067590063356723,0.5300702370805361,0.32461539749677193,0.30549132501511833,0.46421972765037545,0.4145719751280411,0.6194927617036287,0.6837913781935347,0.42697466064690504,0.5312628361779903,0.08394427358334722,0.31092704155262474,0.23729243310901027,0.22830249200893526,0.4825017191440689,0.47659181727783406,0.48570902102061386,0.6064484258966132,0.3193224998390394,0.08359696517720483,0.44492483275018535,0.32054882517260386,0.2983597108477042,0.3558592064024386,0.19928420568351157,0.5169286699953903,0.3677319859511491,0.5103104836534186,0.8141156612689343,0.4764732646580715,0.3834270695710944,0.4512857522116185,0.33345346584946634,0.11452114146163428,0.358258479889491,0.2176772660593751,0.5146621118544314,0.3413932862199621,0.3351070875322726,0.0,0.3021535524066322,0.26911438177956903,0.10878391943321775,0.36209096160083054,0.3970656376671985,0.0,0.02915273635987492,0.39209390889749407,0.39886261480729335,0.0576991377488314,0.4831401716122625,0.7790220032923653,0.24873036395330927,0.47191119354900757,0.3257332037179078,0.4872750050314367,0.33597534754312897,0.2559589746233534,0.46165172112796016,0.259432920934616,0.4491764978872159,0.0,0.3825528965914782,0.4924167220173089,0.43316104112439024,0.5218041164020444,0.6813538440700735,0.33901598499143326,0.5828041418899708,0.5828730085168237,0.061747151088271335,0.410366445995761,0.5015978286259261,0.3274186508537139,0.44373815080302526,0.5438064868131836,0.48152705281678365,0.44661691862600406,0.34492574616375504,0.36543141499368503,0.4275743663651904,0.4152633685504341,0.592819310083496,0.40989184632653075,0.40611249805485206,0.36965152735510665,0.3317917652527933,0.4215795903281747,0.4296502240193436,0.5329216562146559,0.5331599224578503,0.48363394480364774,0.38053796988095756,0.34823263853792685,0.13604424736935816,0.4275617156523288,0.4706016896362041,0.5702019394049207,0.5085227616075063,0.394032738673215,0.3456502127939042,0.523204580638497,0.454459746317707,0.0,0.030099023000826786,0.5492341516451501,0.4187516049820549,0.28989499879808245,0.4435023795753381,0.4366203163100947,0.0,0.5060040770307269,0.11621821150048195,0.2587888940592187,0.6671229125109692,0.5583503443196874,0.5203269452792993,0.01962060448419245,0.6510203582443688,0.3193224998390394,0.0,0.4218032515465502,0.39289499478647094,0.3240000481154641,0.8192444011258739,0.45220655298295775,0.45848915368470866,0.2699344781773183,0.38859631598442923,0.5340142054038644,0.5225813348053843,0.40646359556640166,0.2928008138272926,0.42155680669010076,0.7778524090413762,0.0,0.16383227583528248,0.5424565717494054,0.3757959301793129,0.1895009668369153,0.19168537211889303,0.45718236110899746,0.6218296835275325,0.42550430241995363,0.29780039121265256,0.31092704155262474,0.7120873555663083,0.47940626811700204,0.0,0.3225649604018651,0.28244301850501174,0.2852043862760679,0.6001779570465453,0.4797662857082139,0.0,0.43415995493910475,0.6273976382292401,0.394032738673215,0.6430927504697013,0.09644556762008327,0.2555562059336266,0.6048549909933673,0.4159409573844677,0.6573287232265774,0.0,0.19234003343767958,0.30248364274736594,0.4619100562911236,0.5162317468062099,0.3284956875437921,0.38054271770789305,0.3028548915827576,0.39809588901147686,0.5588062650319363,0.6046990605146372,0.539403527580621,0.38958460518678784,0.4702475546578775,0.28652647187663927,0.596852915618404,0.7959214567640291,0.06105242928880117,0.4762780955340775,0.045447323355697566,0.580324667898356,0.43057353877834303,0.42577987475720536,0.462795744375496,0.4096023994801494,0.49682884324059384,0.5261126420328749,0.6968530258665642,0.366866948998792,0.4630085942912522,0.6002826430321578,0.14537116208419498,0.5736973753379925,0.6691097213101822,0.1255266562530304,0.43958185655870086,0.5146621118544314,0.0,0.24613362837194686,0.36065334360772494,0.36158074726902667,0.648589127336725,0.24775006460000493,0.27127336377323785,0.5578666618861285,0.3915859201207287,0.3572787343021775,0.3792393287537442,0.4149644660059856,0.41749687309241,0.19654456675666643,0.4293971654491434,0.3000281521211885,0.3839887817757234,0.4915323725854085,0.4277402631506727,0.12186784495013425,0.4857586930868928,0.0,0.7037670715731645,0.3413760121523599,0.3380177467659419,0.3681869816963632,0.440310372813991,0.05064199064053265,0.37482915031089903,0.4487406037564413,0.32222474968395887,0.4236009449492383,0.3878920833536871,0.6870500635443327,0.2604734641969405,0.3486938481309263,0.0,0.19168537211889303,0.2625236317988431,0.6664089136986546,0.29309949552087433,0.0,0.2486231972265428,0.3096576116666925,0.38337546871251205,0.5575466070544313,0.8153094234481169,0.4014659354151988,0.6553374279566728,0.3015918842197499,0.5218041164020444,0.10878391943321775,0.3017089338250497,0.4544816890141944,0.33128015665571375,0.3146248959625221,0.32222474968395887,0.44473815972932584,0.6245192850618233,0.4030959330235405,0.4435629195993416,0.7181256613811113,0.43272580468348376,0.11621821150048195,0.5209128916748071,0.5142994786214372,0.4160614468628583,0.2047018099741601,0.45718236110899746,0.2117626700593399,0.38123683535808783,0.04226200575442174,0.4016091761097351,0.2687414924836097,0.4502965478717992,0.11146570195835526,0.43145808715091494,0.8055393073180583,0.18922268452667135,0.5122251612283356,0.3369461078522318,0.7443534494467038,0.6584043498223027,0.16229257262777164,0.4241705825107227,0.4568218530325042,0.34441870106873007,0.438257628003624,0.5796966932204601,0.30708201910120514,0.3837767856958859,0.3724366710254028,0.16383227583528248,0.29309949552087433,0.18201265025021707,0.44009192505039607,0.8348008244005671,0.23202403065879462,0.4534771377060711,0.37587976523086564,0.13914724411212054,0.34384791766038014,0.19026953513182987,0.3523847746182299,0.48975208077863897,0.5799119473491228,0.1444537851540595,0.28683655413466613,0.32066485315684623,0.6470122608160107,0.37450812494776187,0.2034496114024532,0.287267085473226,0.3192630723256925,0.3368185227871191,0.45591901268240376,0.39306493928820607,0.0,0.7442179324703773,0.020103107108688456,0.5372945646582652,0.704111070479773,0.30464987786622577,0.20780440355180985,0.5619958510215559,0.3772195327201706,0.8190966370213955,0.5012563663272548,0.33396682297214064,0.2587888940592187,0.5373859622418391,0.837375806784261,0.5111386038715922,0.4797222462610632,0.45495685714922096,0.48488436049453054,0.07672353637854812,0.5328647139363699,0.6832589631738284,0.0,0.5867902050299001,0.21855179634449917,0.43298660081794893,0.760775867783088,0.5076676322509164,0.025225544503289288,0.7920574327609621,0.3965854160712322,0.5289399869987347,0.45096152183198435,0.5330143503225715,0.29344035499114984,0.0,0.0,0.0,0.6011550142340318,0.6474982044153408,0.5259354333890744,0.2587888940592187,0.521436375398716,0.4016091761097351,0.590056893500993,0.3369461078522318,0.7760063479291248,0.3011358039192318,0.311879770365313,0.5187918707538988,0.13914724411212054,0.318777386405667,0.41113620367462633,0.4695405067503955,0.5843083664590896,0.3944532442377441,0.0804863130050969,0.32949342079100896,0.6090309652814558,0.6182151847597421,0.13023233472690932,0.8689395286895706,0.30496312453064034,0.21443541720877624,0.32292172349465853,0.49815519994253865,0.4011452989559052,0.44207760588800016,0.0,0.5193916566314982,0.514215080077012,0.4261707384997222,0.2707929498231365,0.44661691862600406,0.29032498490982217,0.3908007998268329,0.3279549500681772,0.5307887056123135,0.2603628897465896,0.395996846638219,0.6411728617330259,0.30971265959478744,0.4971712658491857,0.0,0.3369461078522318,0.40089020680646037,0.0814781688629378,0.3859780034749438,0.0,0.0,0.3531562617933499,0.7244541212143862,0.7646518855187386,0.2136605936834748,0.6484866678568533,0.1419310866904573,0.6631759543085954,0.5408240825574877,0.3879109873347374,0.5903523668008224,0.4515364489696615,0.0,0.05313965512693086,0.41258366274302793,0.5407693067121087,0.5406011093534426,0.0576991377488314,0.2908145178310457,0.019549086168488383,0.41689223584127355,0.4714411602933958,0.6641076769986378,0.7219098006483919,0.7450575724733016,0.5117516901523299,0.3432090250204166,0.25574516262532576,0.3654635646061575,0.568629713257021,0.28588432173476763,0.4125323862621495,0.37583061820583563,0.49635724421752603,0.47437735533788083,0.6399121136752788,0.12646829619665623,0.27140320107467975,0.4739917150052736,0.25946125787438934,0.3432090250204166,0.6680434562196018,0.48448355341617344,0.711633189619712,0.3193224998390394,0.39781230448608995,0.5800025354290326,0.49126322134200595,0.47831875419504366,0.5007746615530244,0.3907364012910779,0.513253131165752,0.3517724117477209,0.11621821150048195,0.5218461546742207,0.4544816890141944,0.34790363527506407,0.19734481584037766,0.7076476515676885,0.38003765413263024,0.4369846213118237,0.30193087449195544,0.40036958186211025,0.39184860473276395,0.4005125412889352,0.2773187487514397,0.0,0.0728129244947241,0.6339927426767611,0.3996628003650836,0.6082402575100521,0.46722103432839146,0.4167946028926135,0.6408644010576626,0.6311966721015305,0.3062098888512429,0.5331599224578503,0.38970077213081633,0.4898354928892952,0.7510230352963463,0.48507695318407607,0.0,0.4968666028274511,0.7638595222978392,0.6038802037383013,0.7162363302975834,0.3733793568607717,0.4025500300560141,0.0,0.3862500024689616,0.2369453709051733,0.3192630723256925,0.47295598761679125,0.3405152534480419,0.37716357686706947,0.3731852585988946,0.1255880286524168,0.0,0.6398015387907896,0.2846815238487418,0.250665204411602,0.2695705093330554,0.3833219971626033,0.7283477426687179,0.03422951971100352,0.24360508871071784,0.41908360496078056,0.581024082261102,0.6183740049667017,0.39289499478647094,0.24532884358913898,0.29640680879474,0.0,0.6026580686016113,0.3965854160712322,0.3444894872200899,0.2034496114024532,0.6577900484906738,0.6698030007259652,0.5422291410202636,0.3378649775924264,0.3650541739655404,0.33758374600848373,0.23729243310901027,0.3965854160712322,0.3139863999447645,0.7612254121149644,0.6824159094695972,0.3713361969351042,0.511367249163085,0.27286358409791445,0.43687476808561887,0.31040377110066464,0.0,0.13053626449231925,0.31084545275498265,0.7368411252052762,0.48392854110518924,0.6163419705369679,0.4697854275253076,0.5583289838826827,0.7101994874318178,0.34390572172247325,0.6129847674047796,0.3230008139994218,0.0036196979702772802,0.28520881592153957,0.3229304979581785,0.4222263295130474,0.45870290072200925,0.49440339235067454,0.6088615271385631,0.2015366698384572,0.668325086309918,0.45254381118610854,0.0,0.2590054243422979,0.6944332767728594,0.4349457683350455,0.790358099550303,0.2370331399876623,0.0,0.31280895843756007,0.3675312995441067,0.3982441897932427,0.46722103432839146,0.5559650204867327,0.7070046434134489,0.2719484171521688,0.5544388639136875,0.29344035499114984,0.3732456887868021,0.7288581726422002,0.39574888172252576,0.2683681807465107,0.6476221585145479,0.42750490268791175,0.5966674138239424,0.4734291331036624,0.45429001343555986,0.3432090250204166,0.6939175225403478,0.6230328257097114,0.5199620045785629,0.002590892575257908,0.1419310866904573,0.30765598115136294,0.74710286365244,0.7322098094862214,0.5561016982702143,0.5323721666242032,0.1566897787732512,0.4797603843090765,0.2994191733936721,0.3571832498149451,0.7570274155735255,0.3968157387749094,0.23357812183821092,0.3637388369653486,0.4539745465752496,0.5133622801440711,0.5138366335552118,0.48284761645161134,0.2829741040591264,0.12646829619665623,0.6549374547126916,0.16383227583528248,0.4057958093888334,0.5901720468803853,0.47975609485825166,0.30464987786622577,0.02395925569434121,0.4828428240179383,0.27104244808099387,0.38549257170340767,0.0,0.36585561469556527,0.36261848284387277,0.6482850177676809,0.5576050591302872,0.5324571921888792,0.5160295112671592,0.6042108054383037,0.5991807696517805,0.5695348295152692,0.0,0.697280476256651,0.3694525027687853,0.6049891074114021,0.3075412850332335,0.20229171161929127,0.220474378390216,0.5248243482477422,0.314896194290192,0.7748590466459435,0.18289074348482992,0.44794736325711915,0.3634134700766245,0.5454282280807465,0.6548967063036726,0.6420211904173218,0.302398478158321,0.26097697111644147,0.4839297133881679,0.5446355870407886,0.6378078271426482,0.5974616897989032,0.7097275650629797,0.12741992401463698,0.6657773927924662,0.014042273322152465,0.46619472287709374,0.0,0.3585298120532113,0.2120021793151633,0.5232886515439205,0.3375415399055758,0.14912292196340138,0.3515990394500266,0.47295598761679125,0.3626512211333548,0.28851718334749554,0.7037312216660062,0.3978271109706405,0.2995744499613756,0.5352404104883052,0.23661875754705952,0.2526158036153937,0.5662070339742704,0.2868554877592293,0.01962060448419245,0.725582942263068,0.3531562617933499,0.10216771413614723,0.556987073654708,0.5014973834858234,0.33008420901432933,0.4524249943415104,0.4112124387763466,0.3199536574744053,0.6400404919262683,0.6799832848717987,0.4320456714018984,0.5468939794116625,0.39809588901147686,0.4830145402957102,0.39809588901147686,0.30464987786622577,0.5703764920619449,0.26565038758812887,0.5071461665405297,0.42485043783290577,0.003121298369468062,0.6102550657919543,0.4193454398638409,0.4455087183994092,0.0,0.5276791250374102,0.5000008547789663,0.12646829619665623,0.0,0.28880788514208633,0.12036325754073463,0.18831623778807394,0.5350953705275598,0.693462199022868,0.5302810809905963,0.609406314284983,0.6407865899990179,0.32630138806804065,0.04923055396517728,0.40795324737274063,0.40989668098379806,0.5160679655381422,0.3256468403379189,0.7191313783437678,0.3931855086017615,0.13338258614789034,0.6435199422831336,0.030066809762104074,0.10314523463395675,0.2557584683045252,0.19047728846389067,0.6934688546057677,0.5746963411849326,0.4349369763605636,0.37616915020974095,4.6591582469379667E-4,0.4387575530531068,0.04922915472735656,0.5744939400496374,0.281060331201476,0.1007517318837754,0.20683664331304275,0.4010024414978929,0.649654700360162,0.07566411879070911,0.43665405617202724,0.0,0.7147055343142774,0.361499870652888,0.44958845268806913,0.35426804905355036,0.2564319623941328,0.7192379490112057,0.6372617429625445,0.3883511368521614,0.25987157670281547,0.0,0.39709683456102907,0.2908145178310457,0.5264865933777904,0.42452308466195,0.2634840828167587,0.5626069204302353,0.29990854143324974,0.44450024100270924,0.8083352551343521,0.20338253147707386,0.6829727309300303,0.4046840321615103,0.7603000424767818,0.45237785720819845,0.4510259365352023,0.565030762844791,0.5090960173374319,0.5798491094621656,0.458339281784529,0.3908007998268329,0.3062590348550086,0.4614294118932193,0.3238265539334684,0.5480658966608933,0.23026155990225983,0.37503130058565015,0.0,0.39809588901147686,0.0,0.422921087069993,0.5937819471542605,0.5067768473611503,0.1953718944973417,0.5849145253282471,0.4841425512072718,0.0,0.36447909410440105,0.5736848386494585,0.0,0.5356250633850663,0.5189965561548513,0.7675387423111539,0.2204551945457709,0.5687484036263736,0.0,0.6719772789748708,0.37479764838515783,0.0,0.48128374663785145,0.5758316977779914,0.05246635243470976,0.21516462146260296,0.12646829619665623,0.48144540596161123,0.10878391943321775,0.3501588715905187,0.7560477033759149,0.7793786919473746,0.2434184287344051,0.3573052253728288,0.3098177698055351,0.7246280421637609,0.6227483356863686,0.551931166381685,0.39664287586463587,0.4994201845005066,0.7174557307086269,0.2461635624422267,0.44384159406006674,0.5295630771822535,0.0028677249604741606,0.33795614531013884,0.15160634641496518,0.29309949552087433,0.22923187910248222,0.7682890695195341,0.30385595324857595,0.4534760876202787,0.0,0.5463578315036401,0.3369461078522318,0.617278359820584,0.591241879894767,0.36523994016712846,0.5278450015212244,0.3304455201943124,0.5346708968710385,0.6440570438210729,0.3425854494627778,0.647155935226922,0.3823500372327294,0.6946596958962201,0.3456502127939042,0.5650017307797314,0.3000281521211885,0.5493306497118472,0.7260370309689912,0.6828917478749896,0.2951488873753667,0.28436738187280763,0.33728709456229244,0.3327543521584052,0.39809588901147686,0.5669534167362825,0.5411391863024678};
        List<Double> expectedOutlierScores = Arrays.stream(expectedDoubleOutlierScores).boxed().collect(Collectors.toList());

        assertEquals(expectedClusterLabels, clusterLabels);
        assertEquals(expectedOutlierScores, outlierScores);

        List<Prediction<ClusterID>> predictions = model.predict(testSet);

        int i = 0;
        int[] actualLabelPredictions = new int[testSet.size()];
        double[] actualOutlierScorePredictions = new double[testSet.size()];
        for (Prediction<ClusterID> pred : predictions) {
            actualLabelPredictions[i] = pred.getOutput().getID();
            actualOutlierScorePredictions[i] = pred.getOutput().getScore();
            i++;
        }

        int[] expectedLabelPredictions = {5,3,5,5,3,5,4,4,5,3,3,3,3,4,4,5,4,5,5,4};
        double[] expectedOutlierScorePredictions = {0.04384108680937504,0.04922915472735656,4.6591582469379667E-4,0.025225544503289288,0.04922915472735656,0.0,0.044397942146806146,0.044397942146806146,0.025225544503289288,0.0,0.04922915472735656,0.0,0.0,0.044397942146806146,0.02395925569434121,0.003121298369468062,0.02915273635987492,0.03422951971100352,0.0,0.02915273635987492};

        assertArrayEquals(expectedLabelPredictions, actualLabelPredictions);
        assertArrayEquals(expectedOutlierScorePredictions, actualOutlierScorePredictions);

        URI testData = this.getClass().getResource("/basic-gaussians-predict-with-outliers.csv").toURI();
        CSVDataSource<ClusterID> nextCsvTestSource = new CSVDataSource<>(Paths.get(testData),rowProcessor,false);
        Dataset<ClusterID> nextTestSet = new MutableDataset<>(nextCsvTestSource);

        predictions = model.predict(nextTestSet);

        i = 0;
        actualLabelPredictions = new int[nextTestSet.size()];
        actualOutlierScorePredictions = new double[nextTestSet.size()];
        for (Prediction<ClusterID> pred : predictions) {
            actualLabelPredictions[i] = pred.getOutput().getID();
            actualOutlierScorePredictions[i] = pred.getOutput().getScore();
            i++;
        }

        int[] nextExpectedLabelPredictions = {5,0,3,0,4,0};
        double[] nextExpectedOutlierScorePredictions = {0.04384108680937504,0.837375806784261,0.04922915472735656,0.837375806784261,0.02915273635987492,0.837375806784261};

        assertArrayEquals(nextExpectedLabelPredictions, actualLabelPredictions);
        assertArrayEquals(nextExpectedOutlierScorePredictions, actualOutlierScorePredictions);
    }

    public static void runBasicTrainPredict(HdbscanTrainer trainer) {
        DataSource<ClusterID> gaussianSource = new GaussianClusterDataSource(1000, 1L);
        TrainTestSplitter<ClusterID> splitter = new TrainTestSplitter<>(gaussianSource, 0.8f, 2L);
        Dataset<ClusterID> trainData = new MutableDataset<>(splitter.getTrain());
        Dataset<ClusterID> testData = new MutableDataset<>(splitter.getTest());

        HdbscanModel model = trainer.train(trainData);

        for (HdbscanTrainer.ClusterExemplar e : model.getClusterExemplars()) {
            assertTrue(e.getMaxDistToEdge() > 0.0);
        }

        List<Integer> clusterLabels = model.getClusterLabels();
        List<Double> outlierScores = model.getOutlierScores();
        List<Pair<Integer,List<Feature>>> exemplarLists = model.getClusters();
        List<HdbscanTrainer.ClusterExemplar> exemplars = model.getClusterExemplars();

        assertEquals(exemplars.size(), exemplarLists.size());

        // Check there's at least one exemplar per label
        Set<Integer> exemplarLabels = exemplarLists.stream().map(Pair::getA).collect(Collectors.toSet());
        Set<Integer> clusterLabelSet = new HashSet<>(clusterLabels);
        // Remove the noise label
        clusterLabelSet.remove(Integer.valueOf(0));
        assertEquals(exemplarLabels,clusterLabelSet);

        for (int i = 0; i < exemplars.size(); i++) {
            HdbscanTrainer.ClusterExemplar e = exemplars.get(i);
            Pair<Integer, List<Feature>> p = exemplarLists.get(i);
            assertEquals(model.getFeatureIDMap().size(), e.getFeatures().size());
            assertEquals(p.getB().size(), e.getFeatures().size());
            SGDVector otherFeatures = DenseVector.createDenseVector(
                    new ArrayExample<>(trainData.getOutputFactory().getUnknownOutput(), p.getB()),
                    model.getFeatureIDMap(), false);
            assertEquals(otherFeatures, e.getFeatures());
        }

        int [] expectedIntClusterLabels = {4,3,4,5,3,5,3,4,3,4,5,5,3,4,4,0,3,4,0,5,5,3,3,4,4,4,4,4,4,4,4,4,4,0,4,5,3,5,3,4,3,4,4,3,0,5,0,4,4,4,4,4,5,4,3,4,4,4,4,4,5,3,4,3,5,3,4,5,3,4,0,5,4,4,4,4,4,5,4,4,4,4,4,5,3,4,4,3,4,3,5,5,0,5,4,4,3,5,5,4,5,5,3,5,4,4,3,5,4,5,5,5,4,4,5,5,3,5,4,4,3,5,5,3,5,4,4,5,5,5,3,5,4,5,3,4,3,5,4,4,3,3,5,4,4,5,5,4,3,4,5,4,5,4,3,3,3,4,5,4,5,5,3,4,3,3,4,5,3,5,5,5,5,5,4,4,3,4,5,5,4,4,3,4,3,4,5,4,4,5,4,3,3,0,3,5,5,3,3,3,4,3,3,5,5,5,5,3,5,5,3,5,3,4,5,3,3,3,4,4,3,3,3,5,3,4,5,3,5,5,5,3,5,3,5,4,5,4,4,5,5,5,3,5,4,5,5,4,4,4,5,4,5,4,3,3,4,5,4,4,3,3,3,4,5,4,4,4,4,5,4,4,4,5,3,5,4,5,3,5,3,5,4,4,0,4,4,5,3,4,5,5,0,5,4,5,3,4,3,5,5,4,5,5,5,5,5,5,3,5,4,3,3,5,3,4,5,4,3,5,4,3,3,3,5,4,5,4,5,5,4,3,5,4,5,4,5,4,3,4,5,4,4,5,5,5,3,4,5,4,0,3,5,3,4,3,3,5,5,5,4,4,3,3,4,3,5,3,3,4,3,5,3,4,5,4,4,3,4,4,3,3,5,4,4,5,3,5,3,3,4,5,3,4,5,5,4,4,4,5,5,5,5,3,3,4,4,4,4,4,3,5,4,3,4,4,5,3,5,3,4,5,4,4,5,3,4,4,4,5,5,4,5,0,4,5,3,4,5,4,4,4,5,4,4,4,0,3,4,5,5,4,4,3,3,4,3,3,4,5,5,4,3,5,4,4,4,4,5,4,4,3,4,5,5,4,3,4,5,4,3,5,5,5,3,4,4,4,4,4,4,5,3,3,3,5,5,4,5,3,5,3,5,4,5,3,4,5,4,3,5,4,4,5,5,0,3,3,5,5,3,0,5,5,5,5,3,4,5,4,3,3,4,5,4,4,0,5,3,4,4,4,4,5,5,5,3,5,4,3,3,5,3,4,3,5,3,3,4,3,5,4,3,4,3,0,4,5,5,5,3,4,3,5,5,4,5,4,4,4,5,4,3,4,3,4,5,3,5,4,5,3,0,4,0,4,3,3,4,3,0,3,3,3,3,4,4,5,3,3,5,4,4,4,5,5,5,3,3,4,4,3,4,5,3,4,4,5,3,4,4,4,3,4,4,4,5,4,4,5,5,5,4,4,4,5,5,5,5,4,3,4,3,3,3,4,4,5,4,5,4,4,4,4,4,5,4,5,5,5,4,3,5,3,5,4,5,4,4,5,0,5,3,4,5,4,4,5,3,4,4,3,5,4,4,4,5,3,3,4,4,5,5,5,3,4,3,4,5,5,4,4,3,3,4,4,5,5,5,3,4,3,4,4,4,5,5,5,0,4,5,5,3,3,4,5,4,3,3,4,3,4,5,4,3,4,5,5,3,3,4,4,3,3,5,4,5,3,4,5,4,3,3,4,5,5,5,3,3,4,4,5,5,5,4,5,5,5,4,4,4,5,4,5,5,3,3,4,4,3,5,5,3,3,4,4,5,3,3,3};
        List<Integer> expectedClusterLabels = Arrays.stream(expectedIntClusterLabels).boxed().collect(Collectors.toList());

        double [] expectedDoubleOutlierScores = {0.46676776260759345,0.2743698754772864,0.7559982720268424,0.8501840034553623,0.49318092730464635,0.13138938738160744,0.4713199767058086,0.6252876350317327,0.5993132028604171,0.5099794170903283,0.34739656697344323,0.7877610766946352,0.6725050057122981,0.0,0.3443411864540462,0.942517632028674,0.49375727602750374,0.0,0.8895331356424256,0.6324670047095703,0.42882347542687815,0.49318092730464635,0.691903096844513,0.6380593801053474,0.2406826282408977,0.0,0.6968734399959293,0.3610993140443196,0.5535004360403812,0.6096176323143576,0.0,0.0,0.3913407463849664,0.9519927727728552,0.0,0.5393032152890598,0.6503011262262826,0.1433842216333847,0.49506479112319557,0.5709634323345956,0.4563315958116082,0.44618653226418115,0.44814977073944906,0.0,0.9074703755075781,0.7291450269088865,0.9484293814844095,0.0,0.3705649211930552,0.3480591862782948,0.0,0.7517459138118392,0.5690934599956823,0.6502288567686347,0.6206513888636165,0.6017282507095788,0.5733419619457072,0.7117066450461398,0.7782759723827917,0.0,0.3564466150534611,0.5610358783143924,0.3777803191375566,0.6968916961864624,0.0,0.6017974254583286,0.46129103283467177,0.41698356410558357,0.8424752330761394,0.5904539743502417,0.8830377178678264,0.8611226634391924,0.20674767396012295,0.4730307972339155,0.0,0.5304342181470512,0.43017634165005014,0.4343582676741472,0.0,0.47654625883887125,0.0,0.25196441733320185,0.2957896263676023,0.3640784213318997,0.0,0.2569367496898257,0.40541971866030124,0.6111594683636595,0.5793323777062229,0.8402720631189264,0.5844081900168824,0.4972444475275547,0.8821097291727182,0.3736050635122288,0.3443411864540462,0.0,0.8810705083902441,0.0,0.0,0.0,0.455748881321304,0.27939799074230476,0.8371148472011978,0.7906776310593313,0.16481581471815432,0.0,0.8473854479601578,0.06314528545928999,0.0,0.10155008808627008,0.3964971775769046,0.0,0.3443411864540462,0.6098919291901133,0.6379495148152017,0.5841073563731103,0.5229236206301431,0.6501619239874012,0.3443411864540462,0.5953992476545811,0.5072740714951296,0.4605406727289195,0.0,0.6544956955298067,0.6501619239874012,0.5609881604044372,0.8026896506782976,0.3964971775769046,0.08357327465242192,0.7193239335926954,0.5595574991480672,0.0,0.1995613282017613,0.0,0.8597242790184043,0.6979503825421514,0.7104042746619621,0.5548121181682619,0.2935311018632297,0.4636958976102995,0.7083109193732234,0.471177917299232,0.0,0.7939891118341219,0.24683871216813147,0.3464327881240151,0.7460168123057431,0.7134267350609619,0.5610358783143924,0.07838284850471278,0.7396457383752255,0.7617607303705443,0.47464886817517193,0.3163448961273,0.7773362486663004,0.8263291289832474,0.5238013994386587,0.5675502692728531,0.0,0.46129103283467177,0.0,0.43476375433827963,0.0,0.0,0.8277619726852297,0.8435902856429793,0.0,0.4327059463200057,0.8641362465433343,0.27939799074230476,0.18594335385103455,0.5298320190732928,0.14012035981759297,0.27066293065269187,0.6360710982377022,0.45019911030204196,0.21506286554014598,0.3443411864540462,0.8282719359151842,0.09812661154489999,0.5733419619457072,0.3756037273200026,0.551629899884865,0.0,0.6544956955298067,0.5696608258449514,0.6907048630196866,0.45261858796940857,0.2284755074997018,0.0,0.0,0.6725050057122981,0.5653348091708341,0.8901221625800861,0.5072740714951296,0.2765984401011835,0.08357327465242192,0.6470473237995003,0.7959804069715428,0.5909403594346183,0.514153415940259,0.0,0.9292108460851046,0.5819766000229493,0.0,0.579942440138181,0.8774911291582113,0.05399443648683844,0.6216675811633252,0.41698356410558357,0.5404377149880093,0.14012035981759297,0.2743698754772864,0.3486561149101042,0.49766275174228025,0.7403568247909462,0.6725050057122981,0.7366428541023031,0.31848573305331973,0.0,0.6351806919052676,0.6379936443946175,0.5643094888768054,0.87242048722334,0.45114165259596173,0.4267483686744079,0.4459420844294427,0.4979058181573891,0.6687168793513216,0.6725039248778191,0.5898326395194236,0.3786565035491881,0.49270476278526754,0.6845482002842296,0.5312504911095062,0.0,0.14012035981759297,0.0,0.13260183495549782,0.0,0.1114322036219213,0.0,0.22354672645501728,0.4437011486963448,0.32454746691008174,0.2129513856466727,0.7322362660260833,0.6428127919521037,0.7299583115950901,0.3805190861517057,0.5942874634038553,0.32454746691008174,0.48232688782776534,0.0,0.5079723021903902,0.426792378877326,0.0,0.0,0.0,0.46129103283467177,0.42701054653212456,0.05399443648683844,0.32963857165340793,0.4011402980489066,0.49884143112507695,0.6742625110529403,0.7000703820982973,0.0059186060290421505,0.3935328253717545,0.4982012977088105,0.46129103283467177,0.1884812300740285,0.0,0.0,0.0,0.7193239335926954,0.20322704801088176,0.6147177259392704,0.6386340973679066,0.4605406727289195,0.35336940249769566,0.7532381385481872,0.0,0.0,0.9119502216589748,0.2739356391172154,0.10511679922476258,0.5928945724077263,0.6483155244223532,0.32972277729175326,0.7437779508567764,0.8667982942943174,0.9016466990936328,0.0,0.20095036828617263,0.09796389879511136,0.6237249089180936,0.46217811332893666,0.4874368146961645,0.8015888606177888,0.2129513856466727,0.25867271023886684,0.8627287953882614,0.6387184765952185,0.29477547307621677,0.44990336909740747,0.27939799074230476,0.0,0.719192575186314,0.0752302226040954,0.0,0.7480360862618636,0.8490766015294575,0.3804955800190625,0.6725050057122981,0.41293235299928155,0.7906776310593313,0.5576591657399872,0.5993132028604171,0.11368083044659938,0.0,0.2959490414383299,0.5072740714951296,0.3872053944517456,0.3990149169995906,0.0,0.31715178735852456,0.7169533729847726,0.5178185436513978,0.7049185121521424,0.6968734399959293,0.0,0.02065034905954999,0.1400214190055723,0.5507059666282947,0.3163448961273,0.4481475262869722,0.18097453586463574,0.811581582918492,0.563763712019848,0.08357327465242192,0.053392009649182115,0.7567212136194974,0.8504256359936448,0.8054570184077979,0.8501840034553623,0.5006038683696926,0.4723191896910045,0.39335681832489,0.7128589406590711,0.9126499391266593,0.5993132028604171,0.7707901441751914,0.5051009955803989,0.6729664427879043,0.3872053944517456,0.6256349097006557,0.5146933549477546,0.5596642473643627,0.11368083044659938,0.6248666542874606,0.7404248189769456,0.22821556208077354,0.5893320991429196,0.3935328253717545,0.22354672645501728,0.7087678762850806,0.7944281661194821,0.5404377149880093,0.8020958632147266,0.46174439351502505,0.09812661154489999,0.7492684267597052,0.6309454765188025,0.576131133494547,0.11028289394958157,0.5655946122939484,0.05399443648683844,0.43650020150407365,0.08212338693601973,0.4901722099881468,0.0,0.0,0.0,0.4148561856261437,0.6040842867023796,0.8217703793127248,0.6367390214802099,0.5239122935203155,0.31517820690329956,0.00509618317782945,0.6253843090069545,0.5751062454265111,0.5749814506098023,0.6799761261709416,0.5438395449287226,0.31848573305331973,0.0,0.35152584520905694,0.5004067400291996,0.7291450269088865,0.39649970945668,0.11161437102919114,0.0,0.46368151674524083,0.7904624552413114,0.3443411864540462,0.31848573305331973,0.37130998229165235,0.5733419619457072,0.6544956955298067,0.6316843154288729,0.5617117678592323,0.8786618155909707,0.575985154427317,0.32454746691008174,0.4605406727289195,0.4943123620097287,0.8719502427750575,0.0,0.6210977617501681,0.5526961492564358,0.0,0.3756037273200026,0.8075793400487667,0.6725050057122981,0.39893901604072746,0.3410240139382218,0.2935311018632297,0.635440473010447,0.29477547307621677,0.0,0.02065034905954999,0.9392912491571164,0.42249911335168855,0.14097336145379602,0.6847290646834571,0.5194865825883319,0.14012035981759297,0.7832174963908662,0.4365915265432285,0.3819107449024405,0.6726949923291138,0.4011402980489066,0.3935328253717545,0.25196441733320185,0.881350459326978,0.7349084526542964,0.6047151306067444,0.0,0.20977384411280398,0.4679944192020826,0.6698566773200858,0.0,0.2959490414383299,0.7932391110064335,0.622319399561805,0.8015596575831598,0.39998141687078625,0.4574247863501638,0.17981462714349217,0.3717035453553832,0.6667041054756846,0.553583549266421,0.3443411864540462,0.5433733027536815,0.5148600399821457,0.6968734399959293,0.580828106385362,0.39422048008001054,0.5733419619457072,0.20675485588245224,0.35152584520905694,0.5031988755530088,0.5467067205040299,0.0,0.4414501866925844,0.0,0.49147375734502297,0.7537969758806241,0.05399443648683844,0.0,0.8130406304754614,0.3893369731046228,0.08857940056865066,0.12319636014473168,0.47827834758956966,0.46196635668966657,0.36779495204329093,0.3139968403491683,0.455185529426422,0.0,0.0,0.23496850036493677,0.31517820690329956,0.4727343218057717,0.0,0.6980083836215727,0.7249879488732429,0.5404377149880093,0.36704925127119226,0.0,0.0,0.7939891118341219,0.858959809289114,0.6243592907663799,0.0,0.7193239335926954,0.4487733002302773,0.7295180327424304,0.29131593514163934,0.13649363353017852,0.3562234122805952,0.8627287953882614,0.0,0.8959448055905569,0.697568664523059,0.6847290646834571,0.3811096272517188,0.3921958171277884,0.0,0.9138808799654548,0.8373253417127464,0.03806887171267048,0.0,0.32210719489953354,0.8993257360128568,0.5733419619457072,0.5298320190732928,0.5406291933185892,0.4936169024186612,0.0,0.5676673482591083,0.797644954156777,0.25196441733320185,0.7517459138118392,0.8804787122327714,0.4437951161132294,0.517719961495386,0.6736118674798475,0.0,0.3869796117891282,0.0,0.0,0.11368083044659938,0.49476284568662654,0.0,0.3990149169995906,0.5497567156841348,0.49755861260331113,0.5431034895139442,0.4849594616738354,0.634359329239355,0.6102777431117171,0.5993132028604171,0.029110696378704337,0.0041352367783195065,0.5455357591968216,0.614637828267818,0.3872053944517456,0.8774911291582113,0.0,0.515011903882065,0.5653271117366987,0.6725050057122981,0.8828338637775253,0.0,0.025305516244955806,0.1153305490422244,0.1189992879103362,0.0,0.4623766305089029,0.4972070270025144,0.0,0.19162317880112645,0.0,0.0,0.46322024301962184,0.3564486209165576,0.13221917122566706,0.8074269371585792,0.8086158459470157,0.45215040851165234,0.7250991976553953,0.7104042746619621,0.0,0.7564957221431223,0.6678218872757002,0.49889559243077775,0.6362040007967809,0.8504597507708,0.45590549902450317,0.9009290923658844,0.2935311018632297,0.8837545475640602,0.5878793983623484,0.0,0.7173151984840158,0.6299022163181591,0.0,0.9104797902272275,0.5661891151536319,0.6891663882134245,0.5072740714951296,0.594386514812078,0.5731856857918096,0.0,0.19553532551745423,0.6285842416556849,0.5404377149880093,0.029110696378704337,0.47054972913556337,0.5475804999462761,0.3805190861517057,0.7966719729940861,0.7555806975782535,0.010061020299601542,0.6333336380718192,0.8917306933911169,0.2935311018632297,0.07406510775737263,0.45215040851165234,0.18097453586463574,0.0,0.08132701192855352,0.4366734759781771,0.3564486209165576,0.7310554814333057,0.9204338265893961,0.08471089907230389,0.5696608258449514,0.6922091225884852,0.6279823624589616,0.0,0.3935328253717545,0.0,0.7413065729103836,0.680500524047025,0.6769166895418774,0.5002418053594004,0.0,0.39649970945668,0.0,0.25196441733320185,0.22794789542087268,0.535253084286895,0.797644954156777,0.6736140765300983,0.6390655334750306,0.4613651254516825,0.7655684232457723,0.0,0.3872053944517456,0.6047587670112572,0.7216841523191753,0.6581024749535422,0.2957896263676023,0.0,0.0,0.1358560783357583,0.3443411864540462,0.32972277729175326,0.7412343863236006,0.7137328127320526,0.4807164899348386,0.5816339146436611,0.0,0.39649970945668,0.6554079940503144,0.32081918857815017,0.6250251993493536,0.7099539309159079,0.8460951407432118,0.7210253357230385,0.07792093768838082,0.0,0.8460951407432118,0.617166909604469,0.0,0.17820178754345894,0.9208897313509731,0.1494984069468719,0.6800023209762943,0.0,0.4314997931110507,0.3818456558681199,0.3559937076353532,0.3573443810325546,0.0,0.0,0.4108575710450929,0.5404377149880093,0.3107705511500243,0.34467641363479895,0.6588136178954032,0.0,0.7124877485819077,0.4271754772995946,0.6352932475152177,0.6358395247009956,0.6157498971205291,0.2129513856466727,0.3300832680463701,0.3922526981839124,0.0,0.0,0.5993702342757096,0.6044080434255494,0.0,0.4254461589520476,0.505472792649011,0.5052779575119282,0.0,0.7683354875196753,0.41622494718112346,0.28903657152106876,0.34739656697344323,0.0,0.22045718710077167,0.850119563971185,0.53811553498556,0.0,0.5899675992703288,0.3935328253717545,0.5352299710205285,0.5928945724077263,0.4252236114436363,0.7329731025102499,0.9228363488631618,0.10329887928234749,0.7193239335926954,0.025305516244955806,0.6827262685358917,0.5204591459253809,0.31848573305331973,0.8307996083812397,0.08118104079195632,0.5490352427566516,0.5779985937481655,0.7740622259507297,0.7718601671125394,0.4945464442491214,0.818070291907619,0.2935311018632297,0.5633646723184442,0.0,0.025305516244955806,0.803889349277999,0.04556290658626683,0.6682951293623198,0.0,0.16135790337112854,0.2656863426127436,0.5856638908845988,0.6415288134310423,0.0,0.5826267384294974,0.8404883382141526,0.7401049925075427,0.8552831593916908,0.5688163749124342,0.0,0.0,0.4108575710450929,0.0,0.7858019964605708,0.23346803074513822,0.670754636973998,0.07860444563433111,0.0,0.7286247704137883,0.4334354337345858,0.49880706067428204,0.0,0.5696608258449514,0.29875909495688924,0.5298320190732928,0.18191542983970188,0.3769853117713595,0.43820864595574294,0.7169533729847726,0.7224900394386976,0.41293235299928155,0.5819766000229493,0.4295586290786334,0.936944591291591,0.5404377149880093,0.3935328253717545,0.31848573305331973,0.0,0.7036693377297398,0.02065034905954999,0.4224925490810527,0.11216184489956871,0.42215466113858024,0.0,0.39649970945668,0.4396553712320629,0.8400030552287128,0.6735267975566936};
        List<Double> expectedOutlierScores = Arrays.stream(expectedDoubleOutlierScores).boxed().collect(Collectors.toList());

        assertEquals(expectedClusterLabels, clusterLabels);
        assertEquals(expectedOutlierScores, outlierScores);

        List<Prediction<ClusterID>> predictions = model.predict(testData);

        int i = 0;
        int[] actualLabelPredictions = new int[testData.size()];
        double[] actualOutlierScorePredictions = new double[testData.size()];
        for (Prediction<ClusterID> pred : predictions) {
            actualLabelPredictions[i] = pred.getOutput().getID();
            actualOutlierScorePredictions[i] = pred.getOutput().getScore();
            i++;
        }

        int[] expectedLabelPredictions = {4,5,3,5,5,3,5,4,5,3,5,5,4,4,4,5,3,4,4,3,3,5,4,5,4,5,3,3,4,5,4,4,5,3,4,5,4,4,5,5,3,5,5,5,4,5,3,4,4,5,5,5,3,3,5,4,3,5,5,5,4,5,4,5,3,4,4,3,3,3,4,5,5,5,5,3,4,5,3,5,5,4,4,4,4,4,4,4,4,5,5,3,4,3,3,5,3,5,5,4,4,4,4,3,3,4,4,4,4,4,3,3,5,5,5,4,4,5,4,5,4,5,4,5,4,5,5,5,4,5,4,4,3,5,4,5,5,3,4,5,5,4,5,4,4,3,3,5,5,5,5,4,4,5,4,4,4,4,5,3,5,5,5,3,4,5,4,4,4,4,4,4,5,5,3,4,3,5,5,5,4,5,5,5,4,4,3,4,5,4,4,5,5,5,5,4,5,5,5,5};
        double[] expectedOutlierScorePredictions = {0.08118104079195632,0.0,0.04556290658626683,0.010061020299601542,0.029110696378704337,0.08132701192855352,0.010061020299601542,0.07838284850471278,0.025305516244955806,0.08132701192855352,0.03806887171267048,0.02065034905954999,0.08118104079195632,0.0059186060290421505,0.08118104079195632,0.0,0.08132701192855352,0.0059186060290421505,0.08118104079195632,0.0041352367783195065,0.08132701192855352,0.02065034905954999,0.08471089907230389,0.025305516244955806,0.0,0.0,0.0,0.0,0.08118104079195632,0.06314528545928999,0.07838284850471278,0.0059186060290421505,0.010061020299601542,0.0041352367783195065,0.0059186060290421505,0.010061020299601542,0.08118104079195632,0.08118104079195632,0.029110696378704337,0.010061020299601542,0.08132701192855352,0.03806887171267048,0.03806887171267048,0.029110696378704337,0.07406510775737263,0.02065034905954999,0.04556290658626683,0.07838284850471278,0.08118104079195632,0.0,0.0,0.02065034905954999,0.0041352367783195065,0.0,0.03806887171267048,0.08118104079195632,0.0041352367783195065,0.03806887171267048,0.02065034905954999,0.02065034905954999,0.00509618317782945,0.06314528545928999,0.0059186060290421505,0.029110696378704337,0.07860444563433111,0.08118104079195632,0.08471089907230389,0.0041352367783195065,0.0,0.07860444563433111,0.07838284850471278,0.029110696378704337,0.010061020299601542,0.0,0.06314528545928999,0.0041352367783195065,0.08118104079195632,0.029110696378704337,0.0,0.02065034905954999,0.06314528545928999,0.0,0.08471089907230389,0.00509618317782945,0.08212338693601973,0.08471089907230389,0.00509618317782945,0.08118104079195632,0.08118104079195632,0.0,0.025305516244955806,0.0,0.08118104079195632,0.0041352367783195065,0.0,0.06314528545928999,0.08132701192855352,0.025305516244955806,0.029110696378704337,0.07838284850471278,0.08118104079195632,0.0,0.053392009649182115,0.05399443648683844,0.07860444563433111,0.08118104079195632,0.08471089907230389,0.08212338693601973,0.08118104079195632,0.0,0.04556290658626683,0.08132701192855352,0.03806887171267048,0.0,0.0,0.0,0.08118104079195632,0.029110696378704337,0.0059186060290421505,0.02065034905954999,0.08118104079195632,0.02065034905954999,0.053392009649182115,0.010061020299601542,0.07838284850471278,0.02065034905954999,0.010061020299601542,0.0,0.08118104079195632,0.029110696378704337,0.0059186060290421505,0.0,0.08132701192855352,0.025305516244955806,0.0059186060290421505,0.029110696378704337,0.029110696378704337,0.0,0.00509618317782945,0.025305516244955806,0.010061020299601542,0.08118104079195632,0.029110696378704337,0.08118104079195632,0.0059186060290421505,0.08132701192855352,0.0,0.06314528545928999,0.029110696378704337,0.029110696378704337,0.029110696378704337,0.0059186060290421505,0.08212338693601973,0.02065034905954999,0.08118104079195632,0.0059186060290421505,0.0059186060290421505,0.00509618317782945,0.0,0.08132701192855352,0.025305516244955806,0.025305516244955806,0.02065034905954999,0.0,0.08118104079195632,0.03806887171267048,0.08471089907230389,0.07838284850471278,0.07838284850471278,0.08118104079195632,0.07838284850471278,0.07838284850471278,0.02065034905954999,0.029110696378704337,0.07860444563433111,0.07838284850471278,0.08132701192855352,0.03806887171267048,0.025305516244955806,0.010061020299601542,0.08471089907230389,0.029110696378704337,0.025305516244955806,0.03806887171267048,0.08471089907230389,0.0,0.07860444563433111,0.08212338693601973,0.029110696378704337,0.08118104079195632,0.08118104079195632,0.06314528545928999,0.010061020299601542,0.010061020299601542,0.029110696378704337,0.07838284850471278,0.025305516244955806,0.010061020299601542,0.010061020299601542,0.06314528545928999};

        assertArrayEquals(expectedLabelPredictions, actualLabelPredictions);
        assertArrayEquals(expectedOutlierScorePredictions, actualOutlierScorePredictions);
    }

    @Test
    public void testBasicTrainPredict() {
        runBasicTrainPredict(t);
    }

    @Test
    public void deserializeHdbscanModelV42Test() throws URISyntaxException {
        String serializedModelFilename = "Hdbscan_minClSize7_L2_k7_nt1_v4.2.model";
        URL serializedModelPath = this.getClass().getClassLoader().getResource(serializedModelFilename);

        HdbscanModel model = null;
        try (InputStream is = serializedModelPath.openStream()) {
            model = (HdbscanModel) Model.deserializeFromStream(is);
            if (!model.validate(ClusterID.class)) {
                fail("This is not a Clustering model.");
            }
        } catch (IOException e) {
            fail("There is a problem accessing the serialized model file " + serializedModelPath);
        }

        // In v4.2 models this value is unset and defaults to negative infinity.
        for (HdbscanTrainer.ClusterExemplar e : model.getClusterExemplars()) {
            assertEquals(Double.NEGATIVE_INFINITY, e.getMaxDistToEdge());
        }

        ClusteringFactory clusteringFactory = new ClusteringFactory();
        ResponseProcessor<ClusterID> emptyResponseProcessor = new EmptyResponseProcessor<>(clusteringFactory);
        Map<String, FieldProcessor> regexMappingProcessors = new HashMap<>();
        regexMappingProcessors.put("Feature1", new DoubleFieldProcessor("Feature1"));
        regexMappingProcessors.put("Feature2", new DoubleFieldProcessor("Feature2"));
        regexMappingProcessors.put("Feature3", new DoubleFieldProcessor("Feature3"));
        RowProcessor<ClusterID> rowProcessor = new RowProcessor<>(emptyResponseProcessor,regexMappingProcessors);
        URI testData = this.getClass().getResource("/basic-gaussians-predict.csv").toURI();
        CSVDataSource<ClusterID> csvTestSource = new CSVDataSource<>(Paths.get(testData),rowProcessor,false);
        Dataset<ClusterID> testSet = new MutableDataset<>(csvTestSource);

        List<Prediction<ClusterID>> predictions = model.predict(testSet);

        int i = 0;
        int[] actualLabelPredictions = new int[testSet.size()];
        double[] actualOutlierScorePredictions = new double[testSet.size()];
        for (Prediction<ClusterID> pred : predictions) {
            actualLabelPredictions[i] = pred.getOutput().getID();
            actualOutlierScorePredictions[i] = pred.getOutput().getScore();
            i++;
        }

        int[] expectedLabelPredictions = {5,3,5,5,3,5,4,4,5,3,3,3,3,4,4,5,4,5,5,4};
        double[] expectedOutlierScorePredictions = {0.04384108680937504,0.04922915472735656,4.6591582469379667E-4,0.025225544503289288,0.04922915472735656,0.0,0.044397942146806146,0.044397942146806146,0.025225544503289288,0.0,0.04922915472735656,0.0,0.0,0.044397942146806146,0.02395925569434121,0.003121298369468062,0.02915273635987492,0.03422951971100352,0.0,0.02915273635987492};

        assertArrayEquals(expectedLabelPredictions, actualLabelPredictions);
        assertArrayEquals(expectedOutlierScorePredictions, actualOutlierScorePredictions);
    }

    public static void runEvaluation(HdbscanTrainer trainer) {
        DataSource<ClusterID> gaussianSource = new GaussianClusterDataSource(1000, 1L);
        TrainTestSplitter<ClusterID> splitter = new TrainTestSplitter<>(gaussianSource, 0.7f, 2L);
        Dataset<ClusterID> trainData = new MutableDataset<>(splitter.getTrain());
        Dataset<ClusterID> testData = new MutableDataset<>(splitter.getTest());
        ClusteringEvaluator eval = new ClusteringEvaluator();

        HdbscanModel model = trainer.train(trainData);
        // Test serialization
        Helpers.testModelProtoSerialization(model, ClusterID.class, testData);

        ClusteringEvaluation trainEvaluation = eval.evaluate(model,trainData);
        assertFalse(Double.isNaN(trainEvaluation.adjustedMI()));
        assertFalse(Double.isNaN(trainEvaluation.normalizedMI()));

        ClusteringEvaluation testEvaluation = eval.evaluate(model,testData);
        assertFalse(Double.isNaN(testEvaluation.adjustedMI()));
        assertFalse(Double.isNaN(testEvaluation.normalizedMI()));
    }

    @Test
    public void testTrainTestEvaluation() {
        runEvaluation(t);
    }

    public static void runInvalidExample(HdbscanTrainer trainer) {
        assertThrows(IllegalArgumentException.class, () -> {
            Pair<Dataset<ClusterID>, Dataset<ClusterID>> p = ClusteringDataGenerator.denseTrainTest();
            Model<ClusterID> m = trainer.train(p.getA());
            m.predict(ClusteringDataGenerator.invalidSparseExample());
        });
    }

    @Test
    public void testInvalidExample() {
        runInvalidExample(t);
    }

    public static void runEmptyExample(HdbscanTrainer trainer) {
        assertThrows(IllegalArgumentException.class, () -> {
            Pair<Dataset<ClusterID>, Dataset<ClusterID>> p = ClusteringDataGenerator.denseTrainTest();
            Model<ClusterID> m = trainer.train(p.getA());
            m.predict(ClusteringDataGenerator.emptyExample());
        });
    }

    @Test
    public void testEmptyExample() {
        runEmptyExample(t);
    }

    public static void runSparseData(HdbscanTrainer trainer) {
        Pair<Dataset<ClusterID>,Dataset<ClusterID>> p = ClusteringDataGenerator.sparseTrainTest();
        Model<ClusterID> m = trainer.train(p.getA());
        ClusteringEvaluator e = new ClusteringEvaluator();
        e.evaluate(m,p.getB());
    }

    @Test
    public void testSparseData() {
        runSparseData(t);
    }

    @Test
    public void testContrivedDataset() {
        final HdbscanTrainer trainer = new HdbscanTrainer(100, DistanceType.L2.getDistance(),
                10,1, NeighboursQueryFactoryType.BRUTE_FORCE);

        ClusteringFactory outputFactory = new ClusteringFactory();
        DataSourceProvenance dataProvenance = new SimpleDataSourceProvenance("test", outputFactory);

        List<Example<ClusterID>> dataList = new ArrayList<>();
        for (int n = 0; n < 10; n++) {
            for (double i = 1.0; i <= 2.0; i += 0.1) {
                dataList.add(createClusterExample("A", i));
            }
            for (double i = 10.0; i <= 19.0; i += 0.1) {
                dataList.add(createClusterExample("B", i));
            }
        }

        DataSource<ClusterID> dataSource = new ListDataSource<>(dataList, outputFactory, dataProvenance);
        Dataset<ClusterID> trainData = new MutableDataset<>(dataSource);

        HdbscanModel model = trainer.train(trainData);
        assertEquals(new HashSet<>(model.getClusterLabels()).size(), 2);

        // Predict on the same training data. A good confirmation to make, but don't do this to evaluate a model.
        List<Prediction<ClusterID>> predictions = model.predict(trainData);

        int i = 0;
        for (Prediction<ClusterID> prediction : predictions) {
            if (i % 100 < 10) {
                assertEquals(2, prediction.getOutput().getID());
            }
            else {
                assertEquals(3, prediction.getOutput().getID());
            }
            i++;
        }
    }

    private Example<ClusterID> createClusterExample(String name, double value) {
        return new ArrayExample<>(ClusteringFactory.UNASSIGNED_CLUSTER_ID, new String[]{name}, new double[]{value});
    }

    @Test
    public void loadProtobufModel() throws IOException, URISyntaxException {
        Path path = Paths.get(TestHdbscan.class.getResource("hdbscan-431.tribuo").toURI());
        try (InputStream fis = Files.newInputStream(path)) {
            ModelProto proto = ModelProto.parseFrom(fis);
            HdbscanModel model = (HdbscanModel) Model.deserialize(proto);

            assertEquals("4.3.1", model.getProvenance().getTribuoVersion());

            DataSource<ClusterID> gaussianSource = new GaussianClusterDataSource(1000, 1L);
            TrainTestSplitter<ClusterID> splitter = new TrainTestSplitter<>(gaussianSource, 0.8f, 2L);
            Dataset<ClusterID> testData = new MutableDataset<>(splitter.getTest());
            List<Prediction<ClusterID>> predictions = model.predict(testData);

            int i = 0;
            int[] actualLabelPredictions = new int[testData.size()];
            double[] actualOutlierScorePredictions = new double[testData.size()];
            for (Prediction<ClusterID> pred : predictions) {
                actualLabelPredictions[i] = pred.getOutput().getID();
                actualOutlierScorePredictions[i] = pred.getOutput().getScore();
                i++;
            }

            int[] expectedLabelPredictions = {4,5,3,5,5,3,5,4,5,3,5,5,4,4,4,5,3,4,4,3,3,5,4,5,4,5,3,3,4,5,4,4,5,3,4,5,4,4,5,5,3,5,5,5,4,5,3,4,4,5,5,5,3,3,5,4,3,5,5,5,4,5,4,5,3,4,4,3,3,3,4,5,5,5,5,3,4,5,3,5,5,4,4,4,4,4,4,4,4,5,5,3,4,3,3,5,3,5,5,4,4,4,4,3,3,4,4,4,4,4,3,3,5,5,5,4,4,5,4,5,4,5,4,5,4,5,5,5,4,5,4,4,3,5,4,5,5,3,4,5,5,4,5,4,4,3,3,5,5,5,5,4,4,5,4,4,4,4,5,3,5,5,5,3,4,5,4,4,4,4,4,4,5,5,3,4,3,5,5,5,4,5,5,5,4,4,3,4,5,4,4,5,5,5,5,4,5,5,5,5};
            double[] expectedOutlierScorePredictions = {0.08118104079195632,0.0,0.04556290658626683,0.010061020299601542,0.029110696378704337,0.08132701192855352,0.010061020299601542,0.07838284850471278,0.025305516244955806,0.08132701192855352,0.03806887171267048,0.02065034905954999,0.08118104079195632,0.0059186060290421505,0.08118104079195632,0.0,0.08132701192855352,0.0059186060290421505,0.08118104079195632,0.0041352367783195065,0.08132701192855352,0.02065034905954999,0.08471089907230389,0.025305516244955806,0.0,0.0,0.0,0.0,0.08118104079195632,0.06314528545928999,0.07838284850471278,0.0059186060290421505,0.010061020299601542,0.0041352367783195065,0.0059186060290421505,0.010061020299601542,0.08118104079195632,0.08118104079195632,0.029110696378704337,0.010061020299601542,0.08132701192855352,0.03806887171267048,0.03806887171267048,0.029110696378704337,0.07406510775737263,0.02065034905954999,0.04556290658626683,0.07838284850471278,0.08118104079195632,0.0,0.0,0.02065034905954999,0.0041352367783195065,0.0,0.03806887171267048,0.08118104079195632,0.0041352367783195065,0.03806887171267048,0.02065034905954999,0.02065034905954999,0.00509618317782945,0.06314528545928999,0.0059186060290421505,0.029110696378704337,0.07860444563433111,0.08118104079195632,0.08471089907230389,0.0041352367783195065,0.0,0.07860444563433111,0.07838284850471278,0.029110696378704337,0.010061020299601542,0.0,0.06314528545928999,0.0041352367783195065,0.08118104079195632,0.029110696378704337,0.0,0.02065034905954999,0.06314528545928999,0.0,0.08471089907230389,0.00509618317782945,0.08212338693601973,0.08471089907230389,0.00509618317782945,0.08118104079195632,0.08118104079195632,0.0,0.025305516244955806,0.0,0.08118104079195632,0.0041352367783195065,0.0,0.06314528545928999,0.08132701192855352,0.025305516244955806,0.029110696378704337,0.07838284850471278,0.08118104079195632,0.0,0.053392009649182115,0.05399443648683844,0.07860444563433111,0.08118104079195632,0.08471089907230389,0.08212338693601973,0.08118104079195632,0.0,0.04556290658626683,0.08132701192855352,0.03806887171267048,0.0,0.0,0.0,0.08118104079195632,0.029110696378704337,0.0059186060290421505,0.02065034905954999,0.08118104079195632,0.02065034905954999,0.053392009649182115,0.010061020299601542,0.07838284850471278,0.02065034905954999,0.010061020299601542,0.0,0.08118104079195632,0.029110696378704337,0.0059186060290421505,0.0,0.08132701192855352,0.025305516244955806,0.0059186060290421505,0.029110696378704337,0.029110696378704337,0.0,0.00509618317782945,0.025305516244955806,0.010061020299601542,0.08118104079195632,0.029110696378704337,0.08118104079195632,0.0059186060290421505,0.08132701192855352,0.0,0.06314528545928999,0.029110696378704337,0.029110696378704337,0.029110696378704337,0.0059186060290421505,0.08212338693601973,0.02065034905954999,0.08118104079195632,0.0059186060290421505,0.0059186060290421505,0.00509618317782945,0.0,0.08132701192855352,0.025305516244955806,0.025305516244955806,0.02065034905954999,0.0,0.08118104079195632,0.03806887171267048,0.08471089907230389,0.07838284850471278,0.07838284850471278,0.08118104079195632,0.07838284850471278,0.07838284850471278,0.02065034905954999,0.029110696378704337,0.07860444563433111,0.07838284850471278,0.08132701192855352,0.03806887171267048,0.025305516244955806,0.010061020299601542,0.08471089907230389,0.029110696378704337,0.025305516244955806,0.03806887171267048,0.08471089907230389,0.0,0.07860444563433111,0.08212338693601973,0.029110696378704337,0.08118104079195632,0.08118104079195632,0.06314528545928999,0.010061020299601542,0.010061020299601542,0.029110696378704337,0.07838284850471278,0.025305516244955806,0.010061020299601542,0.010061020299601542,0.06314528545928999};

            assertArrayEquals(expectedLabelPredictions, actualLabelPredictions);
            assertArrayEquals(expectedOutlierScorePredictions, actualOutlierScorePredictions);
        }
    }

    public void generateProtobuf() throws IOException {
        HdbscanTrainer trainer = new HdbscanTrainer(5, DistanceType.L2.getDistance(), 5,2, NeighboursQueryFactoryType.KD_TREE);

        DataSource<ClusterID> gaussianSource = new GaussianClusterDataSource(1000, 1L);
        TrainTestSplitter<ClusterID> splitter = new TrainTestSplitter<>(gaussianSource, 0.8f, 2L);
        Dataset<ClusterID> trainData = new MutableDataset<>(splitter.getTrain());

        HdbscanModel model = trainer.train(trainData);

        Helpers.writeProtobuf(model, Paths.get("src","test","resources","org","tribuo","clustering","hdbscan","hdbscan-431.tribuo"));
    }
}
